Menu
CoddyTech

سرعة تتزايد تدريجيًا

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

تصبح اللعبة مملة إذا لم تتغير مطلقًا، واللعبة التي تبدأ بصعوبة تفقد اللاعبين الجدد. ابدأ بسهولة واجعلها أصعب كلما طال صمود اللاعب.

يحدد الوقت المنقضي منذ بدء اللعبة السرعة. يتذكر reset() وقت البدء، وتحسب كل لقطة السرعة انطلاقًا منه:

seconds = (pygame.time.get_ticks() - start_time) // 1000
speed = 3 + seconds // 5

تزداد قيمة seconds // 5 بمقدار 1 كل خمس ثوانٍ، لذا تسقط الصخور أولًا بسرعة 3 بكسلات في كل لقطة، ثم بسرعة 4 بعد خمس ثوانٍ، و5 بعد عشر ثوانٍ. تحافظ الخطوات الصحيحة على السرعة كعدد صحيح، وهذا ما يحتاج إليه Rect: فهو يخزن بكسلات صحيحة، لذا فإن rock.y += 3.5 سيهمل الجزء النصفي.

يستدعي كل من Enter وR الدالة reset()، لذا تبدأ الساعة من جديد مع كل لعبة، مهما طال عرض القائمة.

challenge icon

التحدي

متوسط
  1. في reset()، عيّن start_time إلى pygame.time.get_ticks().
  2. في play_frame()، احسب عدد seconds منذ start_time، واحسب speed = 3 + seconds // 5.
  3. حرّك كل صخرة إلى الأسفل بمقدار speed بدلًا من 3.

جرّب بنفسك

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
    player = pygame.Rect(220, 300, 40, 40)
    rocks = []
    score = 0
    lives = 3
    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))
    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)
    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 rocks, lives, state
    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())

    kept = []
    for rock in rocks:
        rock.y += 3
        if rock.colliderect(player):
            lives -= 1
        elif rock.top <= 360:
            kept.append(rock)
    rocks = kept
    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":
            rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN and state == "menu":
                reset()
                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()

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

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