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בחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

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

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