Menu
CoddyTech

Ein Monster

Lektion 5 von 20 im Kurs Pygame-Projekt: Verteidige den Bergfried von Coddy.

Ein Monster läuft geradewegs auf den Ritter zu. pygame.Vector2 enthält einen x- und einen y-Wert, die Dezimalzahlen sein können, und du kannst ganze Vector2-Werte addieren und subtrahieren:

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

step zeigt vom Monster zum Ritter, egal wie weit dieser entfernt ist. normalize() behält die Richtung bei, macht den Vektor aber 1 Pixel lang. Multipliziert mit self.speed bewegt sich das Monster daher in jedem Frame genau um seine Geschwindigkeit, und zwar in jede beliebige Richtung. Ein Rect kann nur ganze Zahlen speichern, deshalb wird die genaue Position in self.pos gespeichert und das Rect folgt ihr.

Jede Monsterart bekommt eine Zeile in einer Tabelle. Eine neue Art später hinzuzufügen, erfordert also nur eine Zeile:

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

Monster kommen von außerhalb des Fensters. edge_point() wählt mit random.randint(0, 3) eine Seite und eine zufällige Stelle daran, 24 Pixel außerhalb des Fensters.

challenge icon

Aufgabe

Mittel
  1. import random importieren und die Tabelle MONSTERS mit dem slime hinzufügen.
  2. edge_point() schreiben: Seite 0 ist (random.randint(0, WIDTH), -24), bei 1 entsprechend mit HEIGHT + 24, 2 ist (-24, random.randint(0, HEIGHT)) und bei 3 entsprechend mit WIDTH + 24.
  3. class Monster(pygame.sprite.Sprite) schreiben: __init__(self, kind, pos) übernimmt kind, image und speed aus der Tabelle, speichert pos als Vector2 und legt ein 28 × 28 großes rect an, das darauf zentriert ist; update(self, target) bewegt sich wie oben.
  4. In Night: self.monsters = pygame.sprite.Group() mit einem slime bei edge_point(); update ruft self.monsters.update(self.knight.rect.center) auf. Jeden Monster mit draw vor dem Ritter zeichnen.

Probier es selbst

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

Alle Lektionen in Pygame-Projekt: Verteidige den Bergfried

Übe selbstständig: Pygame-Playground