Menu
CoddyTech

Chông nhọn và trái tim

Thuộc phần Thế giới trò chơi trong hành trình Pygame của Coddy. Bài học 32 trên 36.

Trò chơi cần có hiểm nguy. Nhà thám hiểm có 3 mạng, được biểu thị bằng trái tim. Mỗi lần chạm gai hoặc rơi khỏi hang đều mất một mạng.

Gai chỉ chiếm nửa dưới của ô, nên Rect của chúng là nửa dưới: pygame.Rect(rect.x, rect.y + 18, TILE, 18). Vẽ hình ảnh cao hơn 18 pixel, ngay tại góc ô.

Nhiều mối nguy gây ra cùng một việc: lấy đi một mạng và đưa nhà thám hiểm trở lại điểm xuất phát. Dùng chung một cờ cho chúng và tạo một khối lệnh xử lý cờ đó:

hurt = False
if player.top > HEIGHT:
    hurt = True
for spike in spikes:
    if player.colliderect(spike):
        hurt = True
# sau đó
if hurt:
    lives -= 1
    player.midbottom = start
    vel_y = 0

Ba trái tim nằm thành một hàng ở góc trên bên trái: trái tim đầy ứng với mỗi mạng còn lại, trái tim rỗng ứng với mỗi mạng đã mất.

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))
challenge icon

Thử thách

Trung bình

Khi chạm gai hoặc rơi xuống hố, người chơi mất một mạng.

  1. Tải ba hình ảnh được hiển thị; tạo spikes = [] và lives = 3. Mỗi ^ thêm một Rect ở nửa dưới.
  2. Khi rơi xuống hoặc chạm gai, đặt hurt = True; thêm khối if hurt: sau phần xử lý xu.
  3. Vẽ gai tại (spike.x - camera_x, spike.y - 18) và vẽ các trái tim.

Nhấn Chơi và chạm vào gai: bạn sẽ mất một trái tim. Sau đó nhấn Kiểm tra.

Tự làm thử

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


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] == "#"


walls = []
tiles = []
coins = []
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)

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

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

    if player.top > HEIGHT:
        player.midbottom = start
        vel_y = 0

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

    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))
    screen.blit(player_img, (player.x - camera_x, player.y))
    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()

Tất cả bài học trong Thế giới trò chơi

Tự luyện tập: Playground Pygame