Menu
CoddyTech

רצפה לפער

חלק מהיחידה חוקי המשחק במסלול ה-Pygame של Coddy. שיעור 16 מתוך 29.

הסלעים נופלים מהר יותר, אבל הם עדיין מגיעים כל 800 ms. גם סלעים שמגיעים בתדירות גבוהה יותר הופכים את המשחק לקשה יותר. מתחילים עם מרווח של שנייה ומצמצמים אותו עם הזמן:

interval = 1000 - seconds * 60

אחרי 10 שניות המרווח הוא 400 ms, אחרי 17 שניות הוא קטן מ־0, וטיימר עם מרווח של 0 או פחות נעצר. המשחק צריך גבול תחתון: מרווח מינימלי שהוא לעולם לא יורד מתחתיו. max מחזירה את הגדול מבין המספרים שלה, ולכן היא לעולם לא מאפשרת למרווח לרדת מתחת לערך הראשון:

interval = max(400, 1000 - seconds * 60)

טיימר שומר על המרווח שאיתו הוא הופעל. כדי לשנות אותו, מפעילים אותו שוב: בכל פעם שסלע נופל, מחשבים את המרווח החדש וקוראים ל־set_timer עם הערך הזה. הסלע הבא מגיע אחרי המרווח הזה.

if event.type == SPAWN and state == "play":
    rocks.append(...)
    seconds = (pygame.time.get_ticks() - start_time) // 1000
    interval = max(400, 1000 - seconds * 60)
    pygame.time.set_timer(SPAWN, interval)
challenge icon

אתגר

בינוני
  1. ב־reset(), הפעילו את הטיימר SPAWN למשך 1000 ms.
  2. בכל פעם שסלע נופל, הגדירו interval = max(400, 1000 - seconds * 60) והפעילו שוב את הטיימר SPAWN עם הערך הזה.

נסו בעצמכם

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

    seconds = (pygame.time.get_ticks() - start_time) // 1000
    speed = 3 + seconds // 5
    kept = []
    for rock in rocks:
        rock.y += speed
        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()
quiz iconבחנו את עצמכם

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

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

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