Corações e Golpes
Parte da seção Projetos do Journey de Pygame da Coddy. Lição 25 de 31.
O cavaleiro tem 3 corações. O toque de um slime tira um coração, e, quando chega a 0, o jogo acaba.
pygame.sprite.spritecollide(knight, room.enemies, False) é a lista de inimigos que estão tocando no cavaleiro. False mantém esses inimigos no grupo.
Um slime que desliza pelo cavaleiro fica tocando nele por cerca de 30 quadros. Tirar um coração a cada quadro acabaria com o jogo em meio segundo. Então, depois de ser atingido, o cavaleiro fica protegido por 60 quadros, ou um segundo: knight.hurt faz a contagem regressiva, e nenhum toque é contabilizado enquanto o valor estiver acima de 0.
if knight.hurt > 0:
knight.hurt -= 1
elif pygame.sprite.spritecollide(knight, room.enemies, False):
knight.hearts -= 1
knight.hurt = 60
if knight.hearts == 0:
state = "lost"Mostre ao jogador que ele está protegido: enquanto estiver ferido, desenhe o cavaleiro apenas quando knight.hurt % 10 < 5. Ele pisca: 5 quadros aceso, 5 apagado.
state funciona como em Sky Runner: tudo o que se move fica dentro de if state == "playing":, então, em "lost", a fortaleza fica parada.
Desafio
Médio- Defina
self.hearts = 3eself.hurt = 0para o cavaleiro. - Defina
state = "playing"antes do loop e coloque todo o código de movimentação, da chave, da porta e dos inimigos dentro deif state == "playing":. - Depois que os inimigos se moverem, adicione o teste de dano acima.
- Desenhe o cavaleiro somente enquanto
knight.hurt % 10 < 5. Desenhe 3 corações em(8 + i * 40, 6)paraiem 0, 1, 2:heart_imgenquantoi < knight.hearts; caso contrário,empty_img. - Quando
statefor"lost", exibaGame overna cor (240, 240, 240), centralizado em (336, 240).
Experimente você mesmo
import random
import pygame
TILE = 48
MAP = [
"##############",
"#............#",
"#.P......K...#",
"#............#",
"#....##......D",
"#....##......#",
"##.#######.###",
"#............#",
"#...S....H...#",
"##############",
]
pygame.init()
screen = pygame.display.set_mode((672, 480))
pygame.display.set_caption("Rune Keep")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)
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")
door_img = load("dungeon_door.png")
key_img = load("key.png")
slime_img = load("slime.png")
spider_img = load("spider.png")
heart_img = load("heart.png")
empty_img = load("heart_empty.png")
sword_img = load("sword.png")
potion_img = load("potion_red.png")
def draw(image, rect):
screen.blit(image, image.get_rect(center=rect.center))
def cell_rect(col, row):
rect = pygame.Rect(0, 0, 32, 32)
rect.center = (col * TILE + 24, row * TILE + 24)
return rect
class Enemy(pygame.sprite.Sprite):
def __init__(self, image, rect, dx, dy):
super().__init__()
self.image = image
self.rect = rect
self.dx = dx
self.dy = dy
def update(self, blocks):
self.rect.x += self.dx
self.rect.y += self.dy
if self.rect.collidelist(blocks) != -1:
self.rect.x -= self.dx
self.rect.y -= self.dy
self.dx = -self.dx
self.dy = -self.dy
class Room:
def __init__(self, lines):
self.walls = []
self.enemies = pygame.sprite.Group()
self.start = (72, 72)
self.has_key = False
self.door_open = False
for row, line in enumerate(lines):
for col, char in enumerate(line):
if char == "#":
self.walls.append(pygame.Rect(col * TILE, row * TILE, TILE, TILE))
elif char == "P":
self.start = cell_rect(col, row).center
elif char == "K":
self.key = cell_rect(col, row)
elif char == "D":
self.door = pygame.Rect(col * TILE, row * TILE, TILE, TILE)
elif char == "S":
speed = random.choice([-2, 2])
self.enemies.add(Enemy(slime_img, cell_rect(col, row), speed, 0))
def blocks(self):
if self.door_open:
return self.walls
return self.walls + [self.door]
class Knight(pygame.sprite.Sprite):
def __init__(self, center):
super().__init__()
self.image = knight_img
self.rect = pygame.Rect(0, 0, 32, 32)
self.rect.center = center
def move(self, dx, dy, blocks):
self.rect.x += dx
for block in blocks:
if self.rect.colliderect(block):
if dx > 0:
self.rect.right = block.left
elif dx < 0:
self.rect.left = block.right
self.rect.y += dy
for block in blocks:
if self.rect.colliderect(block):
if dy > 0:
self.rect.bottom = block.top
elif dy < 0:
self.rect.top = block.bottom
room = Room(MAP)
knight = Knight(room.start)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
dx = 0
dy = 0
if keys[pygame.K_LEFT]:
dx = -3
if keys[pygame.K_RIGHT]:
dx = 3
if keys[pygame.K_UP]:
dy = -3
if keys[pygame.K_DOWN]:
dy = 3
knight.move(dx, dy, room.blocks())
knight.rect.clamp_ip(screen.get_rect())
if not room.has_key and knight.rect.colliderect(room.key):
room.has_key = True
if room.has_key and knight.rect.inflate(8, 8).colliderect(room.door):
room.door_open = True
room.enemies.update(room.walls + [room.door])
for row in range(10):
for col in range(14):
screen.blit(floor_img, (col * TILE, row * TILE))
for wall in room.walls:
screen.blit(wall_img, wall)
if not room.door_open:
screen.blit(door_img, room.door)
if not room.has_key:
draw(key_img, room.key)
for enemy in room.enemies:
draw(enemy.image, enemy.rect)
draw(knight.image, knight.rect)
if room.has_key:
screen.blit(key_img, (136, 6))
pygame.display.flip()
clock.tick(60)
pygame.quit()
Todas as lições de Projetos
Pratique por conta própria: Playground de Pygame