Menu
CoddyTech

من كل جانب

الدرس 6 من 20 في دورة مشروع Pygame: الصمود في القلعة على Coddy.

وحش واحد من نوع slime لا يشكّل حشدًا. أنشئ وحشًا جديدًا كل ثانية. تكون قيمة self.time % 60 صفرًا مرة كل 60 إطارًا، لذا يضيف هذا وحشًا مرة كل ثانية:

def spawn(self):
    if self.time % 60 == 0:
        self.monsters.add(Monster("slime", edge_point()))

يُسمّى إنشاء أشياء جديدة توليدًا. خصّص له طريقته الخاصة: ستغيّر الدروس القادمة عدد مرات التوليد ونوعه، وسيكون كل ذلك ضمن spawn.

استدعِه في update قبل أن تتحرك الوحوش، حتى يخطو الوحش الجديد خطوته الأولى في الإطار الذي يظهر فيه.

challenge icon

التحدي

سهل
  1. أزِل الكائن الوحيد من نوع slime من Night.__init__.
  2. اكتب spawn(self): كائن slime عند edge_point() كل 60 إطارًا.
  3. استدعِ self.spawn() في update، بعد تحرّك الفارس وقبل self.monsters.update(...).

جرّب بنفسك

import random
import pygame

WIDTH, HEIGHT = 720, 480
TILE = 48
NIGHT = 60 * 60 * 4
WHITE = (240, 240, 240)

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Hold the Keep")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)


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")
MONSTERS = {
    "slime": {"image": load("slime.png"), "speed": 1.0},
}

courtyard = pygame.Rect(TILE, TILE, WIDTH - 2 * TILE, HEIGHT - 2 * TILE)
background = pygame.Surface((WIDTH, HEIGHT))
for row in range(HEIGHT // TILE):
    for col in range(WIDTH // TILE):
        x = col * TILE
        y = row * TILE
        if courtyard.collidepoint(x, y):
            background.blit(floor_img, (x, y))
        else:
            background.blit(wall_img, (x, y))


def draw(image, center):
    screen.blit(image, image.get_rect(center=center))


def clock_text(frames):
    seconds = frames // 60
    return f"{seconds // 60}:{seconds % 60:02d}"


def edge_point():
    side = random.randint(0, 3)
    if side == 0:
        return (random.randint(0, WIDTH), -24)
    if side == 1:
        return (random.randint(0, WIDTH), HEIGHT + 24)
    if side == 2:
        return (-24, random.randint(0, HEIGHT))
    return (WIDTH + 24, random.randint(0, HEIGHT))


class Knight(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = knight_img
        self.rect = pygame.Rect(0, 0, 24, 24)
        self.rect.center = courtyard.center
        self.speed = 3

    def move(self, keys):
        if keys[pygame.K_LEFT]:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT]:
            self.rect.x += self.speed
        if keys[pygame.K_UP]:
            self.rect.y -= self.speed
        if keys[pygame.K_DOWN]:
            self.rect.y += self.speed
        self.rect.clamp_ip(courtyard)


class Monster(pygame.sprite.Sprite):
    def __init__(self, kind, pos):
        super().__init__()
        self.kind = kind
        self.image = MONSTERS[kind]["image"]
        self.speed = MONSTERS[kind]["speed"]
        self.pos = pygame.Vector2(pos)
        self.rect = pygame.Rect(0, 0, 28, 28)
        self.rect.center = self.pos

    def update(self, target):
        step = pygame.Vector2(target) - self.pos
        if step.length() > 0:
            self.pos += step.normalize() * self.speed
        self.rect.center = self.pos


class Night:
    def __init__(self):
        self.knight = Knight()
        self.time = 0
        self.monsters = pygame.sprite.Group()
        self.monsters.add(Monster("slime", edge_point()))

    def update(self, keys):
        self.time += 1
        self.knight.move(keys)
        self.monsters.update(self.knight.rect.center)


night = Night()

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

    night.update(pygame.key.get_pressed())

    screen.blit(background, (0, 0))
    knight = night.knight
    for monster in night.monsters:
        draw(monster.image, monster.rect.center)
    draw(knight.image, knight.rect.center)
    left = font.render(clock_text(max(0, NIGHT - night.time)) + " until dawn", True, WHITE)
    screen.blit(left, left.get_rect(center=(WIDTH // 2, 24)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

جميع دروس مشروع Pygame: الصمود في القلعة

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