Trái tim
Bài học 7 trên 25 trong khóa học Dự án Pygame: Trấn giữ thành trì của Coddy.
Quái vật chạm vào hiệp sĩ sẽ làm mất một trái tim. Nếu không tạm dừng sau khi bị trúng đòn, quái vật đứng trên hiệp sĩ sẽ làm mất một trái tim ở mỗi khung hình, cả năm trái tim chỉ trong một phần mười hai giây. Vì vậy, khi bị trúng đòn, bộ đếm hurt bắt đầu chạy. Khi bộ đếm này giảm về không, hiệp sĩ không thể bị thương:
def take_hits(self):
knight = self.knight
if knight.hurt > 0:
knight.hurt -= 1
elif pygame.sprite.spritecollideany(knight, self.monsters):
knight.hearts -= 1
knight.hurt = 75spritecollideany(sprite, group) trả về sprite đầu tiên trong nhóm có rect chồng lên nhau, hoặc None.
Giờ đây, trò chơi có các trạng thái: "playing" và "lost". Vòng lặp chỉ chạy night.update khi trò chơi đang ở trạng thái playing, vì vậy khi hết trái tim, mọi thứ sẽ dừng lại tại chỗ.
Thử thách
Trung bìnhQuái vật giờ làm mất tim.
- Cho hiệp sĩ
hearts = 5,max_hearts = 5vàhurt = 0, cònNightcóstate = "playing". - Viết
take_hitsnhư trên; khi còn 0 tim, đặtself.state = "lost". Gọi hàm này cuối cùng trongupdate. - Trong vòng lặp, chỉ cập nhật đêm khi
if night.state == "playing". Khi thua, vẽThe keep has fallenbằngbig_fontcỡ 48, căn giữa tại (360, 200).
Nhấn Chơi rồi đứng yên: trúng năm đòn, pháo đài sẽ thất thủ. Sau đó nhấn Kiểm tra.
Tự làm thử
import random
import pygame
WIDTH, HEIGHT = 720, 480
TILE = 48
NIGHT = 60 * 60 * 4
WHITE = (240, 240, 240)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Hold the Keep")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)
def load(name):
return pygame.image.load("assets/images/" + name).convert_alpha()
floor_img = load("floor.png")
wall_img = load("wall.png")
knight_img = load("knight.png")
MONSTERS = {
"slime": {"image": load("slime.png"), "speed": 1.0},
}
courtyard = pygame.Rect(TILE, TILE, WIDTH - 2 * TILE, HEIGHT - 2 * TILE)
background = pygame.Surface((WIDTH, HEIGHT))
for row in range(HEIGHT // TILE):
for col in range(WIDTH // TILE):
x = col * TILE
y = row * TILE
if courtyard.collidepoint(x, y):
background.blit(floor_img, (x, y))
else:
background.blit(wall_img, (x, y))
def draw(image, center):
screen.blit(image, image.get_rect(center=center))
def clock_text(frames):
seconds = frames // 60
return f"{seconds // 60}:{seconds % 60:02d}"
def edge_point():
side = random.randint(0, 3)
if side == 0:
return (random.randint(0, WIDTH), -24)
if side == 1:
return (random.randint(0, WIDTH), HEIGHT + 24)
if side == 2:
return (-24, random.randint(0, HEIGHT))
return (WIDTH + 24, random.randint(0, HEIGHT))
class Knight(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = knight_img
self.rect = pygame.Rect(0, 0, 24, 24)
self.rect.center = courtyard.center
self.speed = 3
def move(self, keys):
if keys[pygame.K_LEFT]:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT]:
self.rect.x += self.speed
if keys[pygame.K_UP]:
self.rect.y -= self.speed
if keys[pygame.K_DOWN]:
self.rect.y += self.speed
self.rect.clamp_ip(courtyard)
class Monster(pygame.sprite.Sprite):
def __init__(self, kind, pos):
super().__init__()
self.kind = kind
self.image = MONSTERS[kind]["image"]
self.speed = MONSTERS[kind]["speed"]
self.pos = pygame.Vector2(pos)
self.rect = pygame.Rect(0, 0, 28, 28)
self.rect.center = self.pos
def update(self, target):
step = pygame.Vector2(target) - self.pos
if step.length() > 0:
self.pos += step.normalize() * self.speed
self.rect.center = self.pos
class Night:
def __init__(self):
self.knight = Knight()
self.time = 0
self.monsters = pygame.sprite.Group()
def spawn(self):
if self.time % 60 == 0:
self.monsters.add(Monster("slime", edge_point()))
def update(self, keys):
self.time += 1
self.knight.move(keys)
self.spawn()
self.monsters.update(self.knight.rect.center)
night = Night()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
night.update(pygame.key.get_pressed())
screen.blit(background, (0, 0))
knight = night.knight
for monster in night.monsters:
draw(monster.image, monster.rect.center)
draw(knight.image, knight.rect.center)
left = font.render(clock_text(max(0, NIGHT - night.time)) + " until dawn", True, WHITE)
screen.blit(left, left.get_rect(center=(WIDTH // 2, 24)))
pygame.display.flip()
clock.tick(60)
pygame.quit()
Tất cả bài học trong Dự án Pygame: Trấn giữ thành trì
Tự luyện tập: Playground Pygame