Menu
CoddyTech

Sự kiện hẹn giờ

Thuộc phần Luật chơi trong hành trình Pygame của Coddy. Bài học 11 trên 30.

Mỗi tảng đá rơi qua mang lại một điểm. Tính một điểm cho mỗi giây bạn sống sót sẽ công bằng hơn. pygame có thể gửi cho trò chơi của bạn một sự kiện riêng mỗi giây.

Loại sự kiện là các con số. pygame.USEREVENT là loại đầu tiên pygame để dành cho bạn, vậy hãy đặt tên cho sự kiện của mình dựa trên đó:

POINT = pygame.USEREVENT + 1
...
pygame.time.set_timer(POINT, 1000)

Từ đó, một sự kiện POINT sẽ đến mỗi 1000 ms cùng với các sự kiện khác, và bạn xử lý nó như một lần nhấn phím:

if event.type == POINT and state == "play":
    score += 1

Bộ hẹn giờ vẫn chạy ở màn hình menu và màn hình kết thúc trò chơi, vì vậy hãy kiểm tra trạng thái. Gọi set_timer lần nữa sẽ khởi động lại bộ hẹn giờ, đó là lý do nó nằm trong reset(): mỗi ván mới chờ đủ một giây để nhận điểm đầu tiên.

challenge icon

Thử thách

Trung bình

Ghi một điểm cho mỗi giây bạn sống sót.

  1. Thêm POINT = pygame.USEREVENT + 1 sau các màu.
  2. Trong reset(), khởi động bộ hẹn giờ để gửi POINT mỗi 1000 ms.
  3. Khi có sự kiện POINT trong lúc chơi, cộng 1 vào điểm số. Đá rơi qua không còn ghi điểm nữa.

Nhấn Chơi: điểm số tăng mỗi giây một lần. Sau đó nhấn Kiểm tra.

Tự làm thử

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)


def reset():
    global player, rock, score, lives, hit_time
    player = pygame.Rect(220, 300, 40, 40)
    rock = pygame.Rect(random.randint(0, 456), -24, 24, 24)
    score = 0
    lives = 3
    hit_time = -2000


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)
    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 score, lives, state, hit_time
    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())

    rock.y += 4
    if rock.top > 360:
        rock.y = -24
        rock.x = random.randint(0, 456)
        score += 1
    now = pygame.time.get_ticks()
    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 == 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()

Tất cả bài học trong Luật chơi

Tự luyện tập: Playground Pygame