Menu
CoddyTech

המפתח והדלת

חלק מהיחידה פרויקטים במסלול ה-Pygame של Coddy. שיעור 23 מתוך 31.

הדלת בקיר הימני נעולה. האביר אוסף את המפתח כשהוא עובר מעליו, ובעזרת המפתח הדלת נפתחת כשהוא נוגע בה.

דלת נעולה היא עוד דבר שחוסם את האביר. מתודה של Room מחזירה את רשימת ה־Rect שחוסמים אותו:

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 כ־Rect בגודל 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()

כל השיעורים ביחידה פרויקטים

תרגלו בעצמכם: Pygame אונליין