Menu
CoddyTech

المفتاح والباب

جزء من قسم المشاريع في رحلة Pygame على Coddy. الدرس 23 من 31.

الباب في الجدار الأيمن مُغلق. يلتقط الفارس المفتاح بالمشي فوقه، وباستخدام المفتاح يُفتح الباب عندما يلمسه.

الباب المُغلق شيء آخر يعترض طريق الفارس. توفّر إحدى الطرق في Room قائمة Rects التي تمنعه من المرور:

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

للمس الباب حيلة: تدفع move الفارس إلى الخارج منه في كل إطار، لذا لا يتداخل Rect الخاص به مع الباب أبدًا. إن knight.rect.inflate(8, 8) نسخة من Rect الخاص به مكبّرة بمقدار 4 بكسلات من كل جانب، وهذه النسخة تتداخل فعلًا مع الباب الذي يضغط عليه.

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

بعد الباب المفتوح تقع حافة النافذة، لذا أبقِ الفارس داخلها باستخدام clamp_ip. في درس لاحق، يؤدي المدخل إلى الغرفة التالية. أظهِر المفتاح في الأعلى بينما يحمله.

challenge icon

التحدي

متوسط
  1. في Room، اضبط self.has_key = False وself.door_open = False. يحدد K القيمة self.key = cell_rect(col, row)؛ ويحدد D self.door لتكون مستطيلًا بأبعاد 48 في 48 لبلاطته.
  2. أضف الطريقة blocks المذكورة أعلاه وحرّك الفارس باستخدام knight.move(dx, dy, room.blocks()).
  3. بعد التحريك: knight.rect.clamp_ip(screen.get_rect())؛ عندما لا يكون معه مفتاح ويلامس room.key، اضبط room.has_key = True؛ ثم افتح الباب كما سبق.
  4. ارسم الباب باستخدام screen.blit(door_img, room.door) عندما يكون مغلقًا، والمفتاح باستخدام draw(key_img, room.key) حتى يلتقطه، وkey_img عند (136, 6) ما دامت room.has_key تساوي true.

جرّب بنفسك

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

جميع دروس المشاريع

تدرّب بنفسك: Playground لـ Pygame