Menu
CoddyTech

Der Schlüssel und die Tür

Teil des Abschnitts Projekte der Pygame-Journey von Coddy. Lektion 23 von 31.

Die Tür in der rechten Wand ist verschlossen. Der Ritter nimmt den Schlüssel auf, indem er darüberläuft, und mit dem Schlüssel öffnet sich die Tür, wenn er sie berührt.

Eine verschlossene Tür ist ein weiteres Hindernis für den Ritter. Eine Methode in Room liefert die Liste der Rects, die ihn aufhalten:

def blocks(self):
    if self.door_open:
        return self.walls
    return self.walls + [self.door]

Beim Berühren der Tür gibt es einen Haken: move schiebt den Ritter in jedem Frame aus ihr heraus, sodass sein Rect die Tür nie überlappt. knight.rect.inflate(8, 8) ist eine Kopie seines Rect, die auf jeder Seite um 4 Pixel vergrößert wurde, und diese Kopie überlappt die Tür, an die er stößt.

if room.has_key and knight.rect.inflate(8, 8).colliderect(room.door):
    room.door_open = True

Hinter der geöffneten Tür liegt der Rand des Fensters, also halte den Ritter mit clamp_ip im Fenster. In einer späteren Lektion führt die Tür zum nächsten Raum. Zeige den Schlüssel oben an, solange er ihn bei sich trägt.

challenge icon

Aufgabe

Mittel
  1. Setze in Room self.has_key = False und self.door_open = False. Ein K setzt self.key = cell_rect(col, row); ein D setzt self.door auf das 48 mal 48 große Rect seines Feldes.
  2. Füge die obige Methode blocks hinzu und bewege den Ritter mit knight.move(dx, dy, room.blocks()).
  3. Nach der Bewegung: knight.rect.clamp_ip(screen.get_rect()); wenn er keinen Schlüssel hat und room.key berührt, setze room.has_key = True; öffne dann die Tür wie oben beschrieben.
  4. Zeichne die Tür mit screen.blit(door_img, room.door), solange sie geschlossen ist, den Schlüssel mit draw(key_img, room.key), bis er aufgehoben wird, und key_img an (136, 6), solange room.has_key wahr ist.

Probier es selbst

import pygame

TILE = 48
MAP = [
    "##############",
    "#............#",
    "#.P......K...#",
    "#............#",
    "#....##......D",
    "#....##......#",
    "##.#######.###",
    "#............#",
    "#...S....H...#",
    "##############",
]

pygame.init()
screen = pygame.display.set_mode((672, 480))
pygame.display.set_caption("Rune Keep")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)


def load(name):
    return pygame.image.load("assets/images/" + name).convert_alpha()


floor_img = load("floor.png")
wall_img = load("wall.png")
knight_img = load("knight.png")
door_img = load("dungeon_door.png")
key_img = load("key.png")
slime_img = load("slime.png")
spider_img = load("spider.png")
heart_img = load("heart.png")
empty_img = load("heart_empty.png")
sword_img = load("sword.png")
potion_img = load("potion_red.png")


def draw(image, rect):
    screen.blit(image, image.get_rect(center=rect.center))


def cell_rect(col, row):
    rect = pygame.Rect(0, 0, 32, 32)
    rect.center = (col * TILE + 24, row * TILE + 24)
    return rect


class Room:
    def __init__(self, lines):
        self.walls = []
        self.start = (72, 72)
        for row, line in enumerate(lines):
            for col, char in enumerate(line):
                if char == "#":
                    self.walls.append(pygame.Rect(col * TILE, row * TILE, TILE, TILE))
                elif char == "P":
                    self.start = cell_rect(col, row).center


class Knight(pygame.sprite.Sprite):
    def __init__(self, center):
        super().__init__()
        self.image = knight_img
        self.rect = pygame.Rect(0, 0, 32, 32)
        self.rect.center = center

    def move(self, dx, dy, blocks):
        self.rect.x += dx
        for block in blocks:
            if self.rect.colliderect(block):
                if dx > 0:
                    self.rect.right = block.left
                elif dx < 0:
                    self.rect.left = block.right
        self.rect.y += dy
        for block in blocks:
            if self.rect.colliderect(block):
                if dy > 0:
                    self.rect.bottom = block.top
                elif dy < 0:
                    self.rect.top = block.bottom


room = Room(MAP)
knight = Knight(room.start)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    dx = 0
    dy = 0
    if keys[pygame.K_LEFT]:
        dx = -3
    if keys[pygame.K_RIGHT]:
        dx = 3
    if keys[pygame.K_UP]:
        dy = -3
    if keys[pygame.K_DOWN]:
        dy = 3
    knight.move(dx, dy, room.walls)

    for row in range(10):
        for col in range(14):
            screen.blit(floor_img, (col * TILE, row * TILE))
    for wall in room.walls:
        screen.blit(wall_img, wall)
    draw(knight.image, knight.rect)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Alle Lektionen in Projekte

Übe selbstständig: Pygame-Playground