وحش
الدرس 5 من 20 في دورة مشروع Pygame: الصمود في القلعة على Coddy.
يسير وحش مباشرةً نحو الفارس. يحتوي pygame.Vector2 على قيمة x وقيمة y يمكن أن تكونا عشريتين، ويمكنك جمع قيم Vector2 كاملة وطرحها:
step = pygame.Vector2(target) - self.pos
if step.length() > 0:
self.pos += step.normalize() * self.speed
self.rect.center = self.posيشير step من الوحش إلى الفارس، مهما كانت المسافة بينهما. تحافظ normalize() على اتجاهه، لكنها تجعله بطول 1 بكسل، لذا عند ضربه في self.speed يتحرك الوحش بسرعته تمامًا في كل إطار، في أي اتجاه. لا يحتفظ Rect إلا بأعداد صحيحة، لذا يُخزَّن الموقع الدقيق في self.pos ويتبعه Rect.
يحصل كل نوع من الوحوش على صف واحد في جدول، لذا فإن إضافة نوع لاحقًا لا تتطلب إلا سطرًا واحدًا:
MONSTERS = {
"slime": {"image": load("slime.png"), "speed": 1.0},
}تأتي الوحوش من خارج النافذة. تختار edge_point() جانبًا باستخدام random.randint(0, 3) وموقعًا عشوائيًا على امتداده، على بُعد 24 بكسل.
التحدي
متوسط- أدرج
import randomوأضف جدولMONSTERSالذي يحتوي على وحش الوحل. - اكتب
edge_point(): الجانب 0 هو(random.randint(0, WIDTH), -24)، والجانب 1 له القيمة نفسها عندHEIGHT + 24، والجانب 2 هو(-24, random.randint(0, HEIGHT))، والجانب 3 له القيمة نفسها عندWIDTH + 24. - اكتب
class Monster(pygame.sprite.Sprite): تحتفظ__init__(self, kind, pos)بالقيمkindوimageوspeedمن الجدول، وبـposكـVector2، وبـrectأبعاده 28 × 28 ومتمركز حوله؛ أماupdate(self, target)فيتحرك كما سبق. - في
Night: أنشئself.monsters = pygame.sprite.Group()مع وحش وحل واحد عندedge_point()؛ واستدعِupdateالدالةself.monsters.update(self.knight.rect.center). ارسم كل وحش باستخدامdrawقبل الفارس.
جرّب بنفسك
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")
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}"
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 Night:
def __init__(self):
self.knight = Knight()
self.time = 0
def update(self, keys):
self.time += 1
self.knight.move(keys)
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
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