Menu
CoddyTech

Bình thường hay khó

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

Cho người chơi chọn độ khó của trò chơi trước khi bắt đầu. Menu hiển thị hai tùy chọn, và các phím mũi tên chọn một tùy chọn:

elif event.key == pygame.K_LEFT and state == "menu":
    difficulty = "normal"
elif event.key == pygame.K_RIGHT and state == "menu":
    difficulty = "hard"

Các phím mũi tên cũng di chuyển người chơi trong lúc chơi. Kiểm tra state == "menu" giúp tách biệt hai cách sử dụng.

Menu đánh dấu tùy chọn đã chọn để người chơi biết phím Enter sẽ bắt đầu chế độ nào:

if difficulty == "normal":
    normal, hard = "> Normal <", "Hard"
else:
    normal, hard = "Normal", "> Hard <"

Sau đó, trò chơi đọc difficulty tại nơi thiết lập các con số. Ở chế độ Hard, đá bắt đầu di chuyển với tốc độ 6 pixel mỗi khung hình thay vì 3:

if difficulty == "normal":
    speed = 3 + seconds // 5
else:
    speed = 6 + seconds // 5

Đặt difficulty = "normal" một lần trước vòng lặp, không đặt trong reset(), để phím R giữ nguyên lựa chọn.

challenge icon

Thử thách

Trung bình

Để người chơi chọn Normal hoặc Hard.

  1. Đặt difficulty = "normal" trước vòng lặp; trên menu, phím Left đặt thành "normal", phím Right đặt thành "hard".
  2. Căn giữa các tùy chọn tại (160, 260) và (320, 260): > Normal < và Hard, hoặc Normal và > Hard <.
  3. Đá bắt đầu rơi với tốc độ 3 pixel mỗi khung hình ở chế độ Normal, 6 ở chế độ Hard, cộng thêm 1 sau mỗi năm giây.

Nhấn Chơi rồi nhấn Right: Hard được đánh dấu. 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)
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, 1000)


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))
            seconds = (pygame.time.get_ticks() - start_time) // 1000
            interval = max(400, 1000 - seconds * 60)
            pygame.time.set_timer(SPAWN, interval)
        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()

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

Tự luyện tập: Playground Pygame