الوحوش الهلامية في دورية
جزء من قسم المشاريع في رحلة Pygame على Coddy. الدرس 24 من 31.
كل S على الخريطة هو وحش هلامي ينزلق على امتداد صفه بمقدار بكسلين في كل إطار، ويعود عند اصطدامه بجدار.
يحتفظ الكائن الرسومي Enemy بسرعته الخاصة، dx وdy، لذا يمكن للفئة نفسها لاحقًا إنشاء وحوش تتحرك إلى أعلى وأسفل. تحرّكه دالته update، وإذا تداخل الآن مع كتلة، فإنه يتراجع ويعكس اتجاهه:
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تعطي rect.collidelist(rects) فهرس أول Rect في القائمة يتداخل معه، أو -1 إذا لم يتداخل مع أيٍّ منها.
تعيش الوحوش الهلامية في مجموعة، room.enemies. يستدعي room.enemies.update(room.walls + [room.door]) الدالة update لكل وحش هلامي، مع تمرير تلك القائمة إليها. يكون الباب ضمن القائمة دائمًا، لذا لا يضل أي وحش هلامي طريقه إلى خارج باب مفتوح.
تبدأ random.choice([-2, 2]) حركة كل وحش هلامي إلى اليسار أو اليمين، لذا لا تتطابق أي لعبتين.
التحدي
متوسط- أضف
import randomفي الأعلى. - اكتب
class Enemy(pygame.sprite.Sprite)مع__init__(self, image, rect, dx, dy)، بحيث يحتفظ بالقيم الأربع كسمات، وأضف طريقةupdateالمذكورة أعلاه. - في
Room، عيّنself.enemies = pygame.sprite.Group(). عند وجودS، أضفEnemy(slime_img, cell_rect(col, row), speed, 0)معspeed = random.choice([-2, 2]). - في كل إطار، بعد رسم الباب، استدعِ
room.enemies.update(room.walls + [room.door]). - ارسم كل عدو باستخدام
draw(enemy.image, enemy.rect)، قبل الفارس.
جرّب بنفسك
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)
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)
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
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)
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