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.posstep 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.
Aufgabe
Mittelimport randomimportieren und die TabelleMONSTERSmit dem slime hinzufügen.edge_point()schreiben: Seite 0 ist(random.randint(0, WIDTH), -24), bei 1 entsprechend mitHEIGHT + 24, 2 ist(-24, random.randint(0, HEIGHT))und bei 3 entsprechend mitWIDTH + 24.class Monster(pygame.sprite.Sprite)schreiben:__init__(self, kind, pos)übernimmtkind,imageundspeedaus der Tabelle, speichertposals Vector2 und legt ein 28 × 28 großesrectan, das darauf zentriert ist;update(self, target)bewegt sich wie oben.- In
Night:self.monsters = pygame.sprite.Group()mit einem slime beiedge_point();updateruftself.monsters.update(self.knight.rect.center)auf. Jeden Monster mitdrawvor 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