Menu
CoddyTech

أفضل نتيجة وإعادة تشغيل آمنة

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

تعرض شاشة انتهاء اللعبة أفضل نتيجة وتبدأ لعبة جديدة عند الضغط على مفتاح المسافة. تُعيَّن قيمة best مرة واحدة، قبل الحلقة، وخارج reset()، لذا تحتفظ اللعبة الجديدة بها.

يؤدي مفتاح المسافة الآن وظيفة ثالثة على شاشة انتهاء اللعبة:

elif pygame.time.get_ticks() - over_time > 500:
    reset()
    state = "play"

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

challenge icon

التحدي

صعب

اعرض أفضل نتيجة وأعد التشغيل بأمان.

  1. بعد state = "menu"، عيّن best = 0 وover_time = 0. عند الاصطدام، تُعيَّن best = max(best, score) وتُضبط over_time على الوقت الحالي.
  2. تعرض شاشة انتهاء اللعبة Game over وBest: 00120 وPress Space to play again.
  3. هناك، يستدعي مفتاح المسافة reset() وتبدأ اللعبة مجددًا، بعد مرور 500 ms على الأقل منذ الاصطدام.

اضغط «العب» واصطدم: ستظهر أفضل نتيجة، ويبدأ مفتاح المسافة اللعبة من جديد. ثم اضغط «تحقق».

جرّب بنفسك

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)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
INK = (40, 50, 80)

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(),
]


def reset():
    global runner, obstacles, speed, score
    runner = Runner()
    obstacles = pygame.sprite.Group()
    speed = 6
    score = 0
    pygame.time.set_timer(SPAWN, 1500)
    pygame.time.set_timer(POINT, 100)


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


reset()
state = "menu"

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()
            elif state == "menu":
                reset()
                state = "play"
        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)
    if state == "menu":
        show("Sky Runner", big_font, 110)
        show("Press Space to start", font, 170)
    else:
        score_text = font.render(f"{score:05}", True, INK)
        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()
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

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

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