Menu
CoddyTech

العدّ التنازلي للانطلاق

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

يؤدي الضغط على مفتاح Enter إلى إسقاط اللاعب مباشرةً وسط الصخور المتساقطة. يمنحه العدّ التنازلي، 3، 2، 1، لحظةً للاستعداد. هذه حالة إضافية، "countdown"، تعرض اللعبة من دون تحريكها، مع رقم في الأعلى.

يُحسب الرقم انطلاقًا من الوقت المنقضي منذ بدء العدّ التنازلي:

left = 3 - (pygame.time.get_ticks() - countdown_start) // 1000

في الثانية الأولى، تعطي // القيمة 0، لذا تكون قيمة left هي 3؛ ثم 2، ثم 1. عندما تصل إلى 0، تبدأ اللعبة:

def countdown_frame():
    global state
    left = 3 - (pygame.time.get_ticks() - countdown_start) // 1000
    draw_game()
    if left > 0:
        number = big_font.render(str(left), True, WHITE)
        screen.blit(number, number.get_rect(center=(240, 170)))
    else:
        state = "play"

يبدأ كلٌّ من Enter وR العدّ التنازلي، لذا تضبط دالة صغيرة الحالة وتحفظ وقت البدء:

def start_countdown():
    global state, countdown_start
    state = "countdown"
    countdown_start = pygame.time.get_ticks()
challenge icon

التحدي

متوسط
  1. اكتب start_countdown() وcountdown_frame() كما هو موضّح، واستدعِ countdown_frame() عندما تكون الحالة "countdown".
  2. استدعاء Enter في القائمة وR على شاشة انتهاء اللعبة للدالة start_countdown() بدلًا من تعيين "play".
  3. يعرض العدّ التنازلي 3 و2 و1 لمدة ثانية واحدة لكل منها، في المنتصف عند (240, 170).

جرّب بنفسك

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Meteor Dodge")
clock = pygame.time.Clock()
heart = pygame.image.load("assets/images/heart.png").convert_alpha()
heart_empty = pygame.image.load("assets/images/heart_empty.png").convert_alpha()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
WHITE = (240, 240, 240)
PLATE = (60, 60, 90)
POINT = pygame.USEREVENT + 1
SPAWN = pygame.USEREVENT + 2


def reset():
    global player, rocks, score, lives, hit_time, wave, to_spawn
    player = pygame.Rect(220, 300, 40, 40)
    rocks = []
    wave = 1
    to_spawn = 3
    score = 0
    lives = 3
    hit_time = -2000
    pygame.time.set_timer(POINT, 1000)
    pygame.time.set_timer(SPAWN, 800)


def draw_menu():
    screen.fill((30, 30, 46))
    title = big_font.render("Meteor Dodge", True, WHITE)
    title_rect = title.get_rect(center=(240, 140))
    pygame.draw.rect(screen, PLATE, title_rect.inflate(24, 12))
    screen.blit(title, title_rect)
    hint = font.render("Press Enter to play", True, WHITE)
    screen.blit(hint, hint.get_rect(center=(240, 200)))


def draw_game():
    screen.fill((30, 30, 46))
    safe = pygame.time.get_ticks() - hit_time < 1000
    if not safe or pygame.time.get_ticks() // 100 % 2 == 0:
        pygame.draw.rect(screen, (255, 196, 0), player)
    for rock in rocks:
        pygame.draw.rect(screen, (235, 80, 80), rock)
    score_text = font.render(f"{score:05}", True, WHITE)
    score_rect = score_text.get_rect(topright=(470, 10))
    pygame.draw.rect(screen, PLATE, score_rect.inflate(12, 8))
    screen.blit(score_text, score_rect)
    wave_text = font.render(f"Wave {wave}", True, WHITE)
    screen.blit(wave_text, wave_text.get_rect(midtop=(240, 10)))
    for i in range(3):
        if i < lives:
            screen.blit(heart, (10 + i * 40, 10))
        else:
            screen.blit(heart_empty, (10 + i * 40, 10))


def play_frame():
    global score, lives, state, hit_time, rocks, wave, to_spawn
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.x -= 6
    if keys[pygame.K_RIGHT]:
        player.x += 6
    player.clamp_ip(screen.get_rect())

    for rock in rocks:
        rock.y += 4
    rocks = [rock for rock in rocks if rock.top <= 360]
    if to_spawn == 0 and not rocks:
        wave += 1
        to_spawn = wave + 2
    now = pygame.time.get_ticks()
    for rock in rocks:
        if rock.colliderect(player) and now - hit_time > 1000:
            hit_time = now
            lives -= 1
            if lives == 0:
                state = "over"
    draw_game()


def draw_over():
    draw_game()
    message = big_font.render("Game over", True, WHITE)
    screen.blit(message, message.get_rect(center=(240, 160)))
    hint = font.render("Press R to play again", True, WHITE)
    screen.blit(hint, hint.get_rect(center=(240, 200)))


reset()
state = "menu"

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == POINT and state == "play":
            score += 1
        if event.type == SPAWN and state == "play" and to_spawn > 0:
            rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))
            to_spawn -= 1
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN and state == "menu":
                state = "play"
            elif event.key == pygame.K_r and state == "over":
                reset()
                state = "play"

    if state == "menu":
        draw_menu()
    elif state == "play":
        play_frame()
    else:
        draw_over()
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz iconاختبر نفسك

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

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

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