Menu
CoddyTech

Slime Berpatroli

Termasuk bagian Proyek dalam perjalanan Pygame di Coddy. Pelajaran 24 dari 31.

Setiap S di peta adalah slime yang bergerak meluncur sepanjang barisnya dengan kecepatan 2 piksel per frame, lalu berbalik arah saat mencapai dinding.

Sprite Enemy menyimpan kecepatannya sendiri, dx dan dy, sehingga class yang sama nantinya bisa digunakan untuk membuat monster yang bergerak naik turun. update menggerakkannya, lalu jika sekarang bertumpang tindih dengan sebuah blok, sprite itu mundur dan berbalik arah:

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

rect.collidelist(rects) memberikan indeks Rect pertama dalam list yang bertumpang tindih, atau -1 jika tidak ada.

Slime berada di dalam Group, room.enemies. room.enemies.update(room.walls + [room.door]) memanggil update pada setiap slime dengan list tersebut. Pintu selalu ada di dalam list itu, jadi slime tidak pernah berkeliaran keluar melalui pintu yang terbuka.

random.choice([-2, 2]) membuat setiap slime mulai bergerak ke kiri atau ke kanan, sehingga tidak ada dua permainan yang sama.

challenge icon

Tantangan

Sedang
  1. Tambahkan import random di bagian atas.
  2. Tulis class Enemy(pygame.sprite.Sprite) dengan __init__(self, image, rect, dx, dy), yang menyimpan keempatnya sebagai atribut, serta method update di atas.
  3. Di Room, atur self.enemies = pygame.sprite.Group(). Huruf S menambahkan Enemy(slime_img, cell_rect(col, row), speed, 0) dengan speed = random.choice([-2, 2]).
  4. Pada setiap frame, setelah pintu, panggil room.enemies.update(room.walls + [room.door]).
  5. Gambar setiap musuh dengan draw(enemy.image, enemy.rect), sebelum kesatria.

Coba sendiri

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 Room:
    def __init__(self, lines):
        self.walls = []
        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)

    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

    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)
    draw(knight.image, knight.rect)
    if room.has_key:
        screen.blit(key_img, (136, 6))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Proyek

Latihan sendiri: Playground Pygame