Menu
CoddyTech

Encuentra la llave

Parte de la sección Mundos del Journey de Pygame de Coddy. Lección 34 de 36.

Hay una llave en el suelo de la cueva y, en el siguiente paso, abre una puerta. La casilla K es la llave: un Rect llamado key, leído en el bucle del mapa como el inicio P.

Al tocarla, se establece has_key = True, una sola vez:

if not has_key and player.colliderect(key):
    has_key = True

La llave forma parte del nivel hasta entonces, así que se dibuja a través de la cámara. Una vez recogida, pasa a pertenecer al jugador, así que se mueve a la barra superior, junto a los corazones, y se dibuja sin la cámara:

if not has_key:
    screen.blit(key_img, (key.x - camera_x, key.y))
# después de los corazones
if has_key:
    screen.blit(key_img, (130, 8))
challenge icon

Desafío

Intermedio

Coloca una llave en la cueva.

  1. Carga key.png en key_img y establece has_key = False.
  2. En el bucle del mapa, una K establece key = rect.
  3. Después de los blobs, tocar key establece has_key = True.
  4. Dibuja la llave en (key.x - camera_x, key.y) hasta que se cumpla has_key, después en (130, 8).

Pulsa «Jugar» y camina hasta la llave: se mueve a la barra superior. Después, «Comprobar».

Pruébalo tú mismo

import pygame

TILE = 36
WIDTH, HEIGHT = 576, 360
SPEED = 4
GRAVITY = 1
JUMP = -15
MAX_FALL = 12

LEVEL = [
    "................................................................",
    "................................................................",
    "................................................................",
    "................................................................",
    "#..............................................................#",
    "#....................C.........................#####...........#",
    "#......CC...C................CC.....CC.........#####.....CC....#",
    "#....................#.........................D...............#",
    "#.P.........#...E....#...^.......K......E......D.C....^......F.#",
    "#######..####################..##########################..#####",
]

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Moss Caves")
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()


background = pygame.image.load("assets/backgrounds/forest.png").convert_alpha()
grass_img = load("grass.png")
grass_left_img = load("grass_left.png")
grass_right_img = load("grass_right.png")
dirt_img = load("dirt.png")
player_img = load("player.png")
coin_img = load("coin.png")
spikes_img = load("spikes.png")
heart_img = load("heart.png")
heart_empty_img = load("heart_empty.png")
blob_img = load("blob.png")
blob_walk_img = load("blob_walk.png")


def solid(row, col):
    if row < 0 or row >= len(LEVEL) or col < 0 or col >= len(LEVEL[0]):
        return False
    return LEVEL[row][col] == "#"


class Blob(pygame.sprite.Sprite):
    def __init__(self, midbottom):
        super().__init__()
        self.frames = [blob_img, blob_walk_img]
        self.image = blob_img
        self.rect = pygame.Rect(0, 0, 30, 26)
        self.rect.midbottom = midbottom
        self.direction = 1
        self.timer = 0

    def update(self):
        self.timer += 1
        self.image = self.frames[self.timer // 10 % 2]
        self.rect.x += self.direction
        if self.direction > 0:
            ahead = self.rect.right
        else:
            ahead = self.rect.left - 1
        hit_wall = any(self.rect.colliderect(wall) for wall in walls)
        ground_ahead = any(wall.collidepoint(ahead, self.rect.bottom) for wall in walls)
        if hit_wall or not ground_ahead:
            self.rect.x -= self.direction
            self.direction = -self.direction


walls = []
tiles = []
coins = []
spikes = []
blobs = pygame.sprite.Group()
for row, line in enumerate(LEVEL):
    for col, char in enumerate(line):
        rect = pygame.Rect(col * TILE, row * TILE, TILE, TILE)
        if char == "#":
            if solid(row - 1, col):
                image = dirt_img
            elif not solid(row, col - 1) and solid(row, col + 1):
                image = grass_left_img
            elif solid(row, col - 1) and not solid(row, col + 1):
                image = grass_right_img
            else:
                image = grass_img
            walls.append(rect)
            tiles.append((image, rect))
        elif char == "P":
            start = rect.midbottom
        elif char == "C":
            coins.append(rect)
        elif char == "^":
            spikes.append(pygame.Rect(rect.x, rect.y + 18, TILE, 18))
        elif char == "E":
            blobs.add(Blob(rect.midbottom))

level_width = len(LEVEL[0]) * TILE
player = player_img.get_rect(midbottom=start)
vel_y = 0
on_ground = False
camera_x = 0
coins_collected = 0
lives = 3

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            if on_ground:
                vel_y = JUMP
        elif event.type == pygame.KEYUP and event.key in (pygame.K_SPACE, pygame.K_UP):
            if vel_y < -4:
                vel_y = -4

    keys = pygame.key.get_pressed()
    dx = 0
    if keys[pygame.K_LEFT]:
        dx -= SPEED
    if keys[pygame.K_RIGHT]:
        dx += SPEED

    player.x += dx
    for wall in walls:
        if player.colliderect(wall):
            if dx > 0:
                player.right = wall.left
            elif dx < 0:
                player.left = wall.right

    vel_y = min(vel_y + GRAVITY, MAX_FALL)
    player.y += vel_y
    on_ground = False
    for wall in walls:
        if player.colliderect(wall):
            if vel_y > 0:
                player.bottom = wall.top
                on_ground = True
            elif vel_y < 0:
                player.top = wall.bottom
            vel_y = 0

    hurt = False
    if player.top > HEIGHT:
        hurt = True

    for coin in coins[:]:
        if player.colliderect(coin):
            coins.remove(coin)
            coins_collected += 1
    for spike in spikes:
        if player.colliderect(spike):
            hurt = True

    blobs.update()
    for blob in blobs:
        if player.colliderect(blob.rect):
            if vel_y > 0 and player.bottom < blob.rect.centery:
                blob.kill()
                vel_y = -8
            else:
                hurt = True

    if hurt:
        lives -= 1
        player.midbottom = start
        vel_y = 0

    camera_x = player.centerx - WIDTH // 2
    camera_x = max(0, min(camera_x, level_width - WIDTH))

    shift = camera_x // 3 % 72
    for y in range(0, HEIGHT, 72):
        for x in range(-shift, WIDTH, 72):
            screen.blit(background, (x, y))
    for image, rect in tiles:
        screen.blit(image, (rect.x - camera_x, rect.y))
    for coin in coins:
        screen.blit(coin_img, (coin.x - camera_x, coin.y))
    for spike in spikes:
        screen.blit(spikes_img, (spike.x - camera_x, spike.y - 18))
    for blob in blobs:
        spot = blob.image.get_rect(midbottom=(blob.rect.centerx - camera_x, blob.rect.bottom))
        screen.blit(blob.image, spot)
    screen.blit(player_img, (player.x - camera_x, player.y))
    for i in range(3):
        if i < lives:
            screen.blit(heart_img, (10 + i * 40, 8))
        else:
            screen.blit(heart_empty_img, (10 + i * 40, 8))
    text = font.render(f"Coins: {coins_collected}", True, (255, 255, 255))
    screen.blit(text, text.get_rect(topright=(WIDTH - 12, 14)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Todas las lecciones de Mundos

Practica por tu cuenta: Playground de Pygame