Menu
CoddyTech

قائمة لعدّاء السماء

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

تستمد Sky Runner قواعدها من هذا القسم، بدءًا بقائمة. تحتاج اللعبة الجديدة إلى إعادة كل شيء إلى حالته عند البداية، لذا ضع ذلك في reset(): عدّاء جديد، ومجموعة فارغة، والسرعة والنتيجة، وإعادة تشغيل المؤقتين كليهما.

يؤدي مفتاح المسافة الآن وظيفتين، واحدة لكل حالة:

if state == "play":
    runner.jump()
elif state == "menu":
    reset()
    state = "play"

تحتاج القائمة إلى سطرين في الوسط، وستحتاج شاشة انتهاء اللعبة إلى ثلاثة أسطر، لذا ترسم دالة صغيرة سطرًا واحدًا في المنتصف عند x 320:

def show(text, text_font, y):
    picture = text_font.render(text, True, INK)
    screen.blit(picture, picture.get_rect(center=(320, y)))

تنتمي النتيجة إلى اللعبة، لذا لا تعرضها إلا بعد بدء اللعبة، وليس في القائمة.

challenge icon

التحدي

متوسط

أضف قائمة إلى Sky Runner.

  1. اكتب reset() للعدّاء والمجموعة وspeed وscore والمؤقّتين؛ واستدعِها قبل الحلقة واضبط state = "menu".
  2. في القائمة، استخدم show() لعرض Sky Runner بخط big_font وعبارة Press Space to start؛ واعرض النتيجة خارج القائمة فقط.
  3. عند الضغط على مفتاح المسافة في القائمة، استدعِ reset() واضبط state = "play".

اضغط «العب»: يبدأ الضغط على مفتاح المسافة جولة. ثم اضغط «تحقق».

جرّب بنفسك

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)

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


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)
pygame.time.set_timer(POINT, 100)
score = 0
state = "play"

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):
            if state == "play":
                runner.jump()
        if event.type == SPAWN and state == "play":
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))
        if event.type == POINT and state == "play":
            score += 1

    if state == "play":
        speed = min(14, 6 + score // 100)
        runner.update()
        obstacles.update()
        if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
            state = "over"

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    score_text = font.render(f"{score:05}", True, (40, 50, 80))
    screen.blit(score_text, score_text.get_rect(topright=(630, 10)))
    if state == "over":
        message = font.render("Game over", True, (40, 50, 80))
        screen.blit(message, message.get_rect(center=(320, 140)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

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

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