Menu
CoddyTech

Seekor Monster

Pelajaran 5 dari 20 dalam kursus Proyek Pygame: Pertahankan Benteng di Coddy.

Monster berjalan lurus menuju ksatria. pygame.Vector2 menyimpan nilai x dan y yang dapat berupa desimal, dan kamu dapat menjumlahkan serta mengurangkan Vector2 utuh:

step = pygame.Vector2(target) - self.pos
if step.length() > 0:
    self.pos += step.normalize() * self.speed
self.rect.center = self.pos

step mengarah dari monster ke ksatria, sejauh apa pun jaraknya. normalize() mempertahankan arahnya, tetapi membuat panjangnya 1 piksel, jadi dikalikan dengan self.speed, monster bergerak tepat sejauh kecepatannya setiap frame, ke arah mana pun. Rect hanya menyimpan bilangan bulat, jadi posisi tepatnya tersimpan di self.pos dan Rect mengikutinya.

Setiap jenis monster mendapat satu baris dalam tabel, jadi menambahkan jenis baru nanti hanya perlu satu baris:

MONSTERS = {
    "slime": {"image": load("slime.png"), "speed": 1.0},
}

Monster muncul dari luar jendela. edge_point() memilih satu sisi dengan random.randint(0, 3) dan titik acak di sepanjang sisi itu, 24 piksel dari tepinya.

challenge icon

Tantangan

Sedang
  1. Tambahkan import random dan tabel MONSTERS yang berisi slime.
  2. Tulis edge_point(): sisi 0 adalah (random.randint(0, WIDTH), -24), sisi 1 sama, tetapi menggunakan HEIGHT + 24, sisi 2 adalah (-24, random.randint(0, HEIGHT)), dan sisi 3 sama, tetapi menggunakan WIDTH + 24.
  3. Tulis class Monster(pygame.sprite.Sprite): __init__(self, kind, pos) menyimpan kind, image, dan speed dari tabel, pos sebagai Vector2, serta rect berukuran 28 kali 28 yang berpusat padanya; update(self, target) bergerak seperti di atas.
  4. Di dalam Night: self.monsters = pygame.sprite.Group() dengan satu slime di edge_point(); update memanggil self.monsters.update(self.knight.rect.center). Gambar setiap monster dengan draw sebelum knight.

Coba sendiri

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")

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}"


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 Night:
    def __init__(self):
        self.knight = Knight()
        self.time = 0

    def update(self, keys):
        self.time += 1
        self.knight.move(keys)


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
    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()

Semua pelajaran di Proyek Pygame: Pertahankan Benteng

Latihan sendiri: Playground Pygame