Kalpler ve Darbeler
Coddy'nin Pygame Journey'sinin Projeler bölümünün bir parçası. Ders 25 / 31.
Şövalyenin 3 kalbi vardır. Bir slime’ın dokunuşu bir kalp götürür ve kalp sayısı 0 olduğunda oyun biter.
pygame.sprite.spritecollide(knight, room.enemies, False), şövalyeye dokunan düşmanların listesidir. False, onları grupta tutar.
Şövalyenin içinden kayarak geçen bir slime, yaklaşık 30 kare boyunca ona dokunur. Her karede bir kalp kaybetmek, oyunu yarım saniyede bitirirdi. Bu yüzden bir darbe aldıktan sonra şövalye 60 kare, yani bir saniye boyunca güvende olur: knight.hurt bu süreyi geri sayar ve değeri 0'dan büyükken dokunuşlar sayılmaz.
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"Oyuncuya güvende olduğunu göster: şövalye hasar almışken onu yalnızca knight.hurt % 10 < 5 olduğunda çiz. Göz kırpar: 5 kare görünür, 5 kare görünmez.
state, Sky Runner'daki gibi çalışır: hareket eden her şey if state == "playing": koşulunun içinde yer alır; böylece "lost" durumunda kale hareketsiz kalır.
Görev
Orta- Şövalyeye
self.hearts = 3veself.hurt = 0değerlerini verin. - Döngüden önce
state = "playing"olarak ayarlayın ve hareket, anahtar, kapı ve düşman kodlarının tamamınıif state == "playing":bloğunun altına yerleştirin. - Düşmanlar hareket ettikten sonra, yukarıdaki hasar kontrolünü ekleyin.
- Şövalyeyi yalnızca
knight.hurt % 10 < 5iken çizin.iiçin 0, 1, 2 değerlerinde(8 + i * 40, 6)konumunda 3 kalp çizin:i < knight.heartsikenheart_img, aksi hâldeempty_img. statedeğeri"lost"olduğunda,Game overmetnini (240, 240, 240) renginde, (336, 240) konumunda ortalanmış olarak gösterin.
Kendin dene
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()
Projeler bölümündeki tüm dersler
Kendi başına pratik yap: Pygame playground