Tải lúc bắt đầu
Thuộc phần Luật chơi trong hành trình Pygame của Coddy. Bài học 21 trên 30.
Bản ghi đã được lưu; giờ hãy đọc lại khi trò chơi bắt đầu. int(file.read()) chuyển văn bản trong tệp thành một số. Lần đầu tiên sẽ chưa có tệp nào, và open dừng chương trình với lỗi FileNotFoundError.
try và except bắt lỗi đó và thực hiện việc khác thay thế:
def load_best():
try:
with open("highscore.txt") as file:
return int(file.read())
except FileNotFoundError:
return 0
best = load_best()Python chạy khối lệnh try. Nếu open gây ra lỗi FileNotFoundError, chương trình chuyển đến khối lệnh except và trả về 0. Mọi lỗi khác vẫn khiến chương trình dừng lại, đúng như bạn muốn: đó là một bug thực sự.
open("highscore.txt") không có chế độ sẽ mở tệp để đọc.
Trên máy tính, hãy đóng trò chơi rồi chạy lại, điểm cao nhất từ lần trước sẽ hiện trên màn hình kết thúc trò chơi đầu tiên. Trong trình duyệt, điều tương tự xảy ra mỗi khi bạn nhấn nút "Chơi", cho đến khi tải lại trang.
Thử thách
Trung bìnhĐọc điểm cao nhất đã lưu khi trò chơi bắt đầu.
- Viết hàm
load_best(): hàm này trả về số tronghighscore.txt, hoặc 0 nếu không có tệp đó. - Đặt
best = load_best()thay vìbest = 0.
Nhấn “Chơi” rồi để thua: màn hình kết thúc trò chơi hiển thị điểm cao nhất, được đọc từ tệp và lưu lại. 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
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, best
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"
best = max(best, score)
with open("highscore.txt", "w") as file:
file.write(str(best))
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)))
best_text = font.render(f"Best: {best}", True, WHITE)
screen.blit(best_text, best_text.get_rect(center=(240, 240)))
reset()
state = "menu"
best = 0
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()
Tất cả bài học trong Luật chơi
Tự luyện tập: Playground Pygame