Biểu tượng trái tim
Bài học 8 trên 25 trong khóa học Dự án Pygame: Trấn giữ thành trì của Coddy.
Người chơi chưa thể nhìn thấy số trái tim. Vẽ một hình cho mỗi trái tim dọc theo thanh phía trên: trái tim đầy cho mỗi mạng còn lại, trái tim rỗng cho mỗi mạng đã mất. Cách làm tương tự giúp vẽ ba ngôi sao thành một hàng, cách nhau 40 pixel:
for i in range(3):
screen.blit(star_img, (20 + i * 40, 10))Một hiệp sĩ không thể bị thương nên trông như vậy. Khi hurt đếm ngược, chỉ vẽ hiệp sĩ khi knight.hurt % 10 < 5: hiện trong năm khung hình, ẩn trong năm khung hình. Hiệp sĩ nhấp nháy, giúp người chơi hiểu vì sao không có gì làm nó bị thương. Khi hurt bằng 0, 0 % 10 bằng 0, nên hiệp sĩ được vẽ trong mỗi khung hình.
Thử thách
DễHiển thị số trái tim còn lại và làm hiệp sĩ nhấp nháy khi an toàn.
- Tải
heart.pngvàheart_empty.pngthànhheart_imgvàempty_img. - Sau hiệp sĩ, với mỗi
itrongrange(knight.max_hearts), hãy vẽheart_imgnếui < knight.hearts, nếu không thì vẽempty_img, tại(8 + i * 34, 6). - Chỉ vẽ hiệp sĩ khi
knight.hurt % 10 < 5.
Nhấn Chơi và để slime tiếp cận bạn: một trái tim sẽ trống và hiệp sĩ sẽ nhấp nháy. 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)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
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
self.hearts = 5
self.max_hearts = 5
self.hurt = 0
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()
self.state = "playing"
def spawn(self):
if self.time % 60 == 0:
self.monsters.add(Monster("slime", edge_point()))
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 = 75
if knight.hearts <= 0:
self.state = "lost"
def update(self, keys):
self.time += 1
self.knight.move(keys)
self.spawn()
self.monsters.update(self.knight.rect.center)
self.take_hits()
night = Night()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if night.state == "playing":
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)))
if night.state == "lost":
message = big_font.render("The keep has fallen", True, WHITE)
screen.blit(message, message.get_rect(center=(WIDTH // 2, 200)))
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