Menu
CoddyTech

Chìa khóa và cánh cửa

Thuộc phần Dự án trong hành trình Pygame của Coddy. Bài học 25 trên 33.

Cánh cửa trên bức tường bên phải đang khóa. Hiệp sĩ nhặt chìa khóa khi đi qua nó, và khi có chìa khóa, anh ấy sẽ mở được cửa khi chạm vào.

Cánh cửa bị khóa là một vật cản nữa đối với hiệp sĩ. Một phương thức trong Room trả về danh sách các Rect cản đường anh ấy:

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

Việc chạm vào cửa có một điểm cần lưu ý: move đẩy hiệp sĩ ra khỏi cửa ở mỗi khung hình, nên Rect của anh ấy không bao giờ chồng lên cửa. knight.rect.inflate(8, 8) là một bản sao của Rect được nới rộng thêm 4 pixel về mỗi phía, và bản sao đó có chồng lên cánh cửa mà anh ấy đang áp sát.

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

Sau cánh cửa mở là mép cửa sổ, vì vậy hãy giữ hiệp sĩ bên trong bằng clamp_ip. Trong một bài học sau, lối đi qua cửa sẽ dẫn đến căn phòng tiếp theo. Hiển thị chìa khóa ở phía trên khi anh ấy mang nó.

challenge icon

Thử thách

Trung bình

Khóa cửa cho đến khi hiệp sĩ tìm thấy chìa khóa.

  1. Trong Room: self.has_key = False và self.door_open = False; K gán self.key = cell_rect(col, row), D gán self.door thành Rect của ô bản đồ có kích thước 48 x 48.
  2. Thêm blocks(); gọi knight.move(dx, dy, room.blocks()), rồi gọi knight.rect.clamp_ip(screen.get_rect()).
  3. Chạm vào room.key sẽ gán room.has_key = True; sau đó mở cửa như trên.

Nhấn Chơi: cửa vẫn đóng cho đến khi bạn lấy chìa khóa. Sau đó nhấn Kiểm tra.

Tự làm thử

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

Tất cả bài học trong Dự án

Tự luyện tập: Playground Pygame