القلوب والضربات
جزء من قسم المشاريع في رحلة Pygame على Coddy. الدرس 25 من 31.
pygame.sprite.spritecollide(knight, room.enemies, False) هي قائمة الأعداء الذين يلامسون الفارس. تُبقي False الأعداء في المجموعة.
الوحل الذي ينزلق عبر الفارس يلامسه لمدة 30 إطارًا تقريبًا. إن أخذ قلب في كل إطار سينهي اللعبة في نصف ثانية. لذلك، بعد الإصابة، يكون الفارس آمنًا لمدة 60 إطارًا، أي ثانية واحدة: يحصي knight.hurt هذه الإطارات تنازليًا، ولا تُحتسب أي ملامسة ما دامت قيمته أكبر من 0.
if knight.hurt > 0:
knight.hurt -= 1
elif pygame.sprite.spritecollide(knight, room.enemies, False):
knight.hearts -= 1
knight.hurt = 60
if knight.hearts == 0:
state = "lost"knight.hurt % 10 < 5. سيومض: 5 إطارات ظاهرًا و5 إطارات مختفيًا.
يعمل state كما في Sky Runner: كل ما يتحرك يقع ضمن if state == "playing":، لذا عند "lost" تبقى القلعة ساكنة.
التحدي
متوسط- اجعل للفارس
self.hearts = 3وself.hurt = 0. - عيّن
state = "playing"قبل الحلقة، وضع كل التعليمات البرمجية الخاصة بالحركة والمفتاح والباب والأعداء ضمنif state == "playing":. - بعد تحرّك الأعداء، أضف اختبار الضرر المذكور أعلاه.
- ارسم الفارس فقط عندما يتحقق
knight.hurt % 10 < 5. ارسم 3 قلوب عند(8 + i * 40, 6)لقيمiمن 0 إلى 2: استخدمheart_imgعندما يكونi < knight.hearts، وإلا فاستخدمempty_img. - عندما تكون
stateهي"lost"، اعرضGame overباللون (240, 240, 240)، في المنتصف عند (336, 240).
جرّب بنفسك
import random
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 Enemy(pygame.sprite.Sprite):
def __init__(self, image, rect, dx, dy):
super().__init__()
self.image = image
self.rect = rect
self.dx = dx
self.dy = dy
def update(self, blocks):
self.rect.x += self.dx
self.rect.y += self.dy
if self.rect.collidelist(blocks) != -1:
self.rect.x -= self.dx
self.rect.y -= self.dy
self.dx = -self.dx
self.dy = -self.dy
class Room:
def __init__(self, lines):
self.walls = []
self.enemies = pygame.sprite.Group()
self.start = (72, 72)
self.has_key = False
self.door_open = False
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
elif char == "K":
self.key = cell_rect(col, row)
elif char == "D":
self.door = pygame.Rect(col * TILE, row * TILE, TILE, TILE)
elif char == "S":
speed = random.choice([-2, 2])
self.enemies.add(Enemy(slime_img, cell_rect(col, row), speed, 0))
def blocks(self):
if self.door_open:
return self.walls
return self.walls + [self.door]
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.blocks())
knight.rect.clamp_ip(screen.get_rect())
if not room.has_key and knight.rect.colliderect(room.key):
room.has_key = True
if room.has_key and knight.rect.inflate(8, 8).colliderect(room.door):
room.door_open = True
room.enemies.update(room.walls + [room.door])
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)
if not room.door_open:
screen.blit(door_img, room.door)
if not room.has_key:
draw(key_img, room.key)
for enemy in room.enemies:
draw(enemy.image, enemy.rect)
draw(knight.image, knight.rect)
if room.has_key:
screen.blit(key_img, (136, 6))
pygame.display.flip()
clock.tick(60)
pygame.quit()
جميع دروس المشاريع
تدرّب بنفسك: Playground لـ Pygame