Menu
CoddyTech

La llave y la puerta

Parte de la sección Proyectos del Journey de Pygame de Coddy. Lección 23 de 31.

La puerta de la pared derecha está cerrada con llave. El caballero recoge la llave al pasar por encima y, con la llave, la puerta se abre cuando la toca.

Una puerta cerrada con llave es un obstáculo más para el caballero. Un método de Room proporciona la lista de Rects que lo detienen:

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

Hay una particularidad al tocar la puerta: move empuja al caballero fuera de ella en cada fotograma, así que su Rect nunca se superpone a la puerta. knight.rect.inflate(8, 8) es una copia de su Rect ampliada en 4 píxeles por cada lado, y esa copia sí se superpone a la puerta contra la que está apoyado.

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

Más allá de la puerta abierta está el borde de la ventana, así que mantén al caballero dentro con clamp_ip. En una lección posterior, la puerta llevará a la siguiente habitación. Muestra la llave en la parte superior mientras la lleva.

challenge icon

Desafío

Intermedio
  1. En Room, establece self.has_key = False y self.door_open = False. Una K establece self.key = cell_rect(col, row); una D establece self.door en el Rect de 48 por 48 de su baldosa.
  2. Añade el método blocks anterior y mueve al caballero con knight.move(dx, dy, room.blocks()).
  3. Después de moverlo: knight.rect.clamp_ip(screen.get_rect()); cuando no tenga una llave y toque room.key, establece room.has_key = True; después, abre la puerta como se indicó anteriormente.
  4. Dibuja la puerta con screen.blit(door_img, room.door) mientras esté cerrada, la llave con draw(key_img, room.key) hasta que la recoja y key_img en (136, 6) mientras room.has_key sea verdadero.

Pruébalo tú mismo

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()

Todas las lecciones de Proyectos

Practica por tu cuenta: Playground de Pygame