Kỷ lục mới
Thuộc phần Luật chơi trong hành trình Pygame của Coddy. Bài học 22 trên 30.
Vượt qua thành tích tốt nhất của bạn là khoảnh khắc đáng ăn mừng. Trò chơi nên thông báo điều đó trên màn hình kết thúc, nhưng chỉ khi bạn lập được thành tích mới.
Thứ tự của hai dòng lệnh quyết định điều đó. Trước tiên, hãy so sánh điểm số với thành tích cũ, rồi cập nhật thành tích tốt nhất:
new_record = score > best
best = max(best, score)Đổi thứ tự hai dòng lệnh, và best đã giữ điểm số khi bạn so sánh, nên score > best không bao giờ đúng.
score > best là một phép so sánh, nên new_record giữ giá trị True hoặc False. Màn hình kết thúc kiểm tra giá trị này:
if new_record:
record = font.render("New record!", True, (255, 220, 90))
screen.blit(record, record.get_rect(center=(240, 110)))Điểm số bằng thành tích tốt nhất không phải là kỷ lục mới. Vì vậy, điều kiện kiểm tra là >, không phải >=.
Thử thách
Trung bìnhĂn mừng điểm số cao nhất mới.
- Khi trò chơi kết thúc, đặt
new_record = score > besttrước khi cập nhậtbest. - Trên màn hình kết thúc trò chơi, khi
new_recordlà true, hiển thịNew record!bằng màu(255, 220, 90), căn giữa tại (240, 110).
Nhấn Chơi và ghi điểm trước khi thua: New record! sẽ hiển thị màu vàng. 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 load_best():
try:
with open("highscore.txt") as file:
return int(file.read())
except FileNotFoundError:
return 0
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 = load_best()
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()
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Luật chơi
Tự luyện tập: Playground Pygame