قلوب
الدرس 7 من 20 في دورة مشروع Pygame: الصمود في القلعة على Coddy.
الوحش الذي يصل إلى الفارس يكلّفه قلبًا. من دون توقّف بعد الإصابة، سيأخذ الوحش الواقف على الفارس قلبًا في كل إطار، أي القلوب الخمسة كلها في اثني عشر من الثانية. لذلك تبدأ الإصابة عدّادًا، hurt، وأثناء تناقصه لا يمكن لأي شيء إيذاء الفارس:
def take_hits(self):
knight = self.knight
if knight.hurt > 0:
knight.hurt -= 1
elif pygame.sprite.spritecollideany(knight, self.monsters):
knight.hearts -= 1
knight.hurt = 75تعطي spritecollideany(sprite, group) أول كائن في المجموعة يتداخل مستطيله، أو None.
أصبحت اللعبة الآن ذات حالات: "playing" و"lost". لا تشغّل الحلقة night.update إلا أثناء اللعب، لذا عندما تنفد القلوب يتوقف كل شيء في مكانه.
أثناء تناقص hurt، ارسم الفارس فقط عندما تكون knight.hurt % 10 < 5: فهو يومض، ويرى اللاعب سبب عدم تأثره بأي شيء.
التحدي
متوسط- اجعل قلوب الفارس
hearts = 5، وmax_hearts = 5، وhurt = 0؛ واجعلNightفي الحالةstate = "playing". - اكتب
take_hitsكما في الأعلى؛ وعندما يصل عدد القلوب إلى 0، عيّنself.state = "lost". واستدعِها أخيرًا فيupdate. - في الحلقة، حدّث فقط عند تحقق
if night.state == "playing"، وارسم الفارس فقط عندما يتحققknight.hurt % 10 < 5. - حمّل
heart.pngوheart_empty.pngفيheart_imgوempty_img. ولكل قلب منmax_hearts، ارسم قلبًا ممتلئًا أو فارغًا عند(8 + i * 34, 6). - أنشئ
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)، وعند الخسارة، ارسم"The keep has fallen"في الوسط عند (360, 200).
جرّب بنفسك
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()
def spawn(self):
if self.time % 60 == 0:
self.monsters.add(Monster("slime", edge_point()))
def update(self, keys):
self.time += 1
self.knight.move(keys)
self.spawn()
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