Menu
CoddyTech

الاصطدام

جزء من قسم قواعد اللعبة في رحلة Pygame على Coddy. الدرس 27 من 29.

إن ملامسة عائق تنهي الجولة. تُرجع pygame.sprite.spritecollideany(sprite, group) أول كائن من المجموعة يلامس الكائن، أو None.

افتراضيًا، تقارن المستطيلات. تحتوي الصور على زوايا شفافة، ولا سيما صورة الكتلة، لذا قد يتداخل مستطيلان من دون أن تتلامس الأجزاء التي تراها. يتيح وسيط ثالث إجراء اختبار أكثر إنصافًا:

if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
    state = "over"

تقارن collide_mask وحدات البكسل المرسومة في الصور وتتجاهل الأجزاء الشفافة. وهكذا يصبح الاصطدام حادثةً يراها اللاعب فعلًا.

تعمل الحالة كما في Meteor Dodge: لا تحدث التحديثات والقفزات وظهور العوائق الجديدة إلا عندما تكون "play"، وترسم شاشة انتهاء اللعبة صورةً ثابتة للعبة مع رسالة.

challenge icon

التحدي

متوسط
  1. أضف خطًا من assets/fonts/pixel.ttf بحجم 32، وأضف state = "play".
  2. فقط عندما تكون الحالة "play": اقفز، وأضف العوائق، وحدّث العداء والعوائق.
  3. عندما يلمس العداء عائقًا (collide_mask)، عيّن الحالة إلى "over".
  4. عند انتهاء اللعبة، اعرض Game over باللون (40, 50, 80) في المنتصف عند (320, 140).

جرّب بنفسك

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()

SKY = (140, 200, 240)
GROUND = (90, 160, 80)
GROUND_Y = 260
GRAVITY = 1
SPAWN = pygame.USEREVENT + 1


class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.frames = [
            pygame.image.load("assets/images/player.png").convert_alpha(),
            pygame.image.load("assets/images/player_walk.png").convert_alpha(),
        ]
        self.image = self.frames[0]
        self.step = 0
        self.rect = self.image.get_rect(midbottom=(100, GROUND_Y))
        self.vy = 0

    def jump(self):
        if self.rect.bottom == GROUND_Y:
            self.vy = -16

    def update(self):
        self.vy += GRAVITY
        self.rect.y += self.vy
        if self.rect.bottom >= GROUND_Y:
            self.rect.bottom = GROUND_Y
            self.vy = 0
        if self.rect.bottom == GROUND_Y:
            self.step += 1
            self.image = self.frames[self.step // 8 % 2]
        else:
            self.image = self.frames[1]


class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = random.choice(obstacle_images)
        self.rect = self.image.get_rect(midbottom=(664, GROUND_Y))

    def update(self):
        self.rect.x -= speed
        if self.rect.right < 0:
            self.kill()


obstacle_images = [
    pygame.image.load("assets/images/spike_ball.png").convert_alpha(),
    pygame.image.load("assets/images/blob.png").convert_alpha(),
]
runner = Runner()
obstacles = pygame.sprite.Group()
speed = 6
pygame.time.set_timer(SPAWN, 1500)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            runner.jump()
        if event.type == SPAWN:
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))

    runner.update()
    obstacles.update()

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

جميع دروس قواعد اللعبة

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