Menu
CoddyTech

Tường chặn hiệp sĩ

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

Kỵ sĩ di chuyển bằng các phím mũi tên, mỗi khung hình 3 pixel, còn tường chặn kỵ sĩ giống như các bệ trong Moss Caves: di chuyển theo trục x, đẩy ra khỏi mọi bức tường mà kỵ sĩ chồng lên, rồi làm tương tự theo trục y. Xử lý từng trục một giúp bạn biết kỵ sĩ va vào phía nào.

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

Đọc các phím mũi tên mỗi khung hình vào dx và dy, như trong Catch the Blocks, rồi truyền các bức tường trong căn phòng:

keys = pygame.key.get_pressed()
dx = 0
dy = 0
if keys[pygame.K_LEFT]:
    dx = -3
# Làm tương tự với phím sang phải, lên và xuống
knight.move(dx, dy, room.walls)
challenge icon

Thử thách

Khó

Điều khiển hiệp sĩ di chuyển và dừng lại khi gặp tường.

  1. Thêm phương thức move(dx, dy, blocks) ở trên vào Knight.
  2. Mỗi khung hình, đặt dx thành -3 khi nhấn Left hoặc 3 khi nhấn Right, và đặt dy thành -3 khi nhấn Up hoặc 3 khi nhấn Down, nếu không thì đặt thành 0.
  3. Sau đó gọi knight.move(dx, dy, room.walls).

Nhấn Chơi rồi đi vào tường: hiệp sĩ sẽ dừng lại khi chạm tường. 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


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

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

    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