Menu
CoddyTech

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.

challenge icon

Görev

Orta
  1. Şövalyeye self.hearts = 3 ve self.hurt = 0 değerlerini verin.
  2. 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.
  3. Düşmanlar hareket ettikten sonra, yukarıdaki hasar kontrolünü ekleyin.
  4. Şövalyeyi yalnızca knight.hurt % 10 < 5 iken çizin. i için 0, 1, 2 değerlerinde (8 + i * 40, 6) konumunda 3 kalp çizin: i < knight.hearts iken heart_img, aksi hâlde empty_img.
  5. state değeri "lost" olduğunda, Game over metnini (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