Menu
CoddyTech

Un monstre

Leçon 5 sur 20 du cours Projet Pygame : Défendez le donjon de Coddy.

Un monstre marche tout droit vers le chevalier. pygame.Vector2 contient une coordonnée x et une coordonnée y qui peuvent avoir des décimales, et tu peux additionner et soustraire des Vector2 entiers :

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

step pointe du monstre vers le chevalier, quelle que soit la distance qui les sépare. normalize() conserve sa direction, mais lui donne une longueur de 1 pixel ; multiplié par self.speed, le monstre se déplace exactement à sa vitesse à chaque image, dans n’importe quelle direction. Un Rect ne contient que des nombres entiers, donc la position exacte se trouve dans self.pos et le Rect la suit.

Chaque type de monstre occupe une ligne dans une table, donc ajouter un type plus tard ne nécessite qu’une ligne :

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

Les monstres arrivent de l’extérieur de la fenêtre. edge_point() choisit un côté avec random.randint(0, 3) et un emplacement aléatoire le long de ce côté, à 24 pixels à l’extérieur.

challenge icon

Défi

Moyen
  1. import random et ajoute le tableau MONSTERS avec le monstre glu.
  2. Écris edge_point() : le côté 0 est (random.randint(0, WIDTH), -24), le côté 1 utilise la même coordonnée avec HEIGHT + 24, le côté 2 est (-24, random.randint(0, HEIGHT)) et le côté 3 utilise la même coordonnée avec WIDTH + 24.
  3. Écris class Monster(pygame.sprite.Sprite) : __init__(self, kind, pos) conserve kind, image et speed du tableau, pos sous forme de Vector2 et un rect de 28 par 28 centré sur cette position ; update(self, target) se déplace comme précédemment.
  4. Dans Night : self.monsters = pygame.sprite.Group() avec un monstre glu à edge_point() ; update appelle self.monsters.update(self.knight.rect.center). Dessine chaque monstre avec draw avant le chevalier.

Essayez vous-même

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

Toutes les leçons de Projet Pygame : Défendez le donjon

Entraînez-vous par vous-même : Playground Pygame