Herzen
Lektion 7 von 20 im Kurs Pygame-Projekt: Verteidige den Bergfried von Coddy.
Ein Monster, das den Ritter erreicht, kostet ein Herz. Ohne eine Pause nach einem Treffer würde ein Monster, das auf dem Ritter steht, in jedem Frame ein Herz abziehen, alle fünf innerhalb einer Zwölftelsekunde. Ein Treffer startet also einen Zähler, hurt, und solange er herunterzählt, kann nichts dem Ritter schaden:
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) gibt das erste Sprite in der Gruppe zurück, dessen Rect überlappt, oder None.
Das Spiel hat jetzt Zustände: "playing" und "lost". Die Schleife führt night.update nur während des Spielens aus, sodass alles dort stehen bleibt, wo es ist, wenn die Herzen aufgebraucht sind.
Solange hurt herunterzählt, zeichne den Ritter nur, wenn knight.hurt % 10 < 5: Er blinkt, und der Spieler sieht, warum nichts Schaden anrichtet.
Aufgabe
Mittel- Gib dem Ritter
hearts = 5,max_hearts = 5undhurt = 0; setze beiNightstate = "playing". - Schreibe
take_hitswie oben; wenn die Herzen 0 erreichen, setzeself.state = "lost". Rufe die Funktion zuletzt inupdateauf. - Aktualisiere in der Schleife nur bei
if night.state == "playing"und zeichne den Ritter nur, wennknight.hurt % 10 < 5. - Lade
heart.pngundheart_empty.pngalsheart_imgundempty_img. Zeichne für jedes dermax_heartsein volles oder leeres Herz an die Position(8 + i * 34, 6). - Erstelle
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)und zeichne bei einer Niederlage"The keep has fallen"zentriert bei (360, 200).
Probier es selbst
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()
Alle Lektionen in Pygame-Projekt: Verteidige den Bergfried
Übe selbstständig: Pygame-Playground