Cœurs
Leçon 7 sur 20 du cours Projet Pygame : Défendez le donjon de Coddy.
Un monstre qui atteint le chevalier lui coûte un cœur. Sans pause après un coup, un monstre se tenant sur le chevalier lui ferait perdre un cœur à chaque image, les cinq en un douzième de seconde. Un coup lance donc un compteur, hurt, et tant qu’il décompte, rien ne peut blesser le chevalier :
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) renvoie le premier sprite du groupe dont le rectangle chevauche celui du sprite donné, ou None.
Le jeu a maintenant des états : "playing" et "lost". La boucle n’exécute night.update que pendant le jeu, de sorte que lorsque les cœurs sont épuisés, tout s’arrête là où il se trouve.
Pendant que hurt décompte, dessine le chevalier uniquement lorsque knight.hurt % 10 < 5 : il clignote, et le joueur comprend pourquoi rien ne le blesse.
Défi
Moyen- Attribue au chevalier
hearts = 5,max_hearts = 5ethurt = 0; attribue àNightstate = "playing". - Écris
take_hitscomme ci-dessus ; lorsque le nombre de cœurs atteint 0, définisself.state = "lost". Appelle cette méthode en dernier dansupdate. - Dans la boucle, effectue la mise à jour uniquement si
if night.state == "playing", et dessine le chevalier uniquement lorsqueknight.hurt % 10 < 5. - Charge
heart.pngetheart_empty.pngsous les nomsheart_imgetempty_img. Pour chacun desmax_hearts, affiche un cœur plein ou vide à(8 + i * 34, 6). - Crée
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)et, en cas de défaite, dessine"The keep has fallen"au centre de (360, 200).
Essayez vous-même
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()
Toutes les leçons de Projet Pygame : Défendez le donjon
Entraînez-vous par vous-même : Playground Pygame