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

כל השיעורים ביחידה חוקי המשחק

תרגלו בעצמכם: Pygame אונליין