Menu
CoddyTech

La clé et la porte

Fait partie de la section Projets du Journey Pygame de Coddy. Leçon 23 sur 31.

La porte du mur de droite est verrouillée. Le chevalier ramasse la clé en marchant dessus et, avec la clé, la porte s’ouvre lorsqu’il la touche.

Une porte verrouillée est un obstacle de plus pour le chevalier. Une méthode de Room fournit la liste des Rects qui l’arrêtent :

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

Toucher la porte a une particularité : move repousse le chevalier hors de celle-ci à chaque image, donc son Rect ne chevauche jamais la porte. knight.rect.inflate(8, 8) est une copie de son Rect agrandie de 4 pixels de chaque côté, et cette copie chevauche bien la porte contre laquelle il est appuyé.

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

Au-delà de la porte ouverte se trouve le bord de la fenêtre : garde donc le chevalier à l’intérieur avec clamp_ip. Dans une leçon ultérieure, l’embrasure mènera à la pièce suivante. Affiche la clé en haut lorsqu’il la porte.

challenge icon

Défi

Moyen
  1. Dans Room, définis self.has_key = False et self.door_open = False. Un K définit self.key = cell_rect(col, row) ; un D définit self.door comme le Rect de 48 par 48 de sa tuile.
  2. Ajoute la méthode blocks ci-dessus et déplace le chevalier avec knight.move(dx, dy, room.blocks()).
  3. Après le déplacement : knight.rect.clamp_ip(screen.get_rect()) ; s’il n’a pas de clé et touche room.key, définis room.has_key = True ; ouvre ensuite la porte comme ci-dessus.
  4. Affiche la porte avec screen.blit(door_img, room.door) lorsqu’elle est fermée, la clé avec draw(key_img, room.key) jusqu’à ce qu’elle soit ramassée, et key_img à (136, 6) lorsque room.has_key est vrai.

Essayez vous-même

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

Toutes les leçons de Projets

Entraînez-vous par vous-même : Playground Pygame