Menu
CoddyTech

Va chạm

Thuộc phần Luật chơi trong hành trình Pygame của Coddy. Bài học 27 trên 30.

Chạm vào chướng ngại vật sẽ kết thúc lượt chơi. pygame.sprite.spritecollideany(sprite, group) trả về sprite đầu tiên trong nhóm chạm vào sprite, hoặc None.

Mặc định, hàm này so sánh các hình chữ nhật. Hình ảnh có các góc trong suốt, đặc biệt là blob, nên hai hình chữ nhật có thể chồng lên nhau dù không có gì bạn nhìn thấy chạm vào nhau. Đối số thứ ba chọn phép kiểm tra chính xác hơn:

if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
    state = "over"

collide_mask so sánh các điểm ảnh được vẽ trong hình và bỏ qua những điểm ảnh trong suốt. Khi đó, va chạm sẽ đúng là một vụ va chạm mà người chơi có thể nhìn thấy.

Trạng thái hoạt động giống như trong Meteor Dodge: trò chơi chỉ cập nhật, nhân vật chỉ nhảy và chướng ngại vật mới chỉ xuất hiện khi trạng thái là "play". Màn hình kết thúc trò chơi sẽ hiển thị trò chơi đã đóng băng cùng một thông báo.

challenge icon

Thử thách

Trung bình

Kết thúc lượt chạy khi nhân vật chạy va vào chướng ngại vật.

  1. Thêm phông chữ assets/fonts/pixel.ttf ở cỡ 32 và state = "play".
  2. Chỉ khi trạng thái là "play": cho nhân vật nhảy, thêm chướng ngại vật, cập nhật nhân vật và các chướng ngại vật.
  3. Một va chạm (collide_mask) đặt trạng thái thành "over"; sau đó hiển thị Game over bằng màu (40, 50, 80), căn giữa tại (320, 140).

Nhấn Chơi rồi đứng yên: Game over sẽ hiển thị và mọi thứ dừng lại. Sau đó nhấn Kiểm tra.

Tự làm thử

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()

SKY = (140, 200, 240)
GROUND = (90, 160, 80)
GROUND_Y = 260
GRAVITY = 1
SPAWN = pygame.USEREVENT + 1


class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.frames = [
            pygame.image.load("assets/images/player.png").convert_alpha(),
            pygame.image.load("assets/images/player_walk.png").convert_alpha(),
        ]
        self.image = self.frames[0]
        self.step = 0
        self.rect = self.image.get_rect(midbottom=(100, GROUND_Y))
        self.vy = 0

    def jump(self):
        if self.rect.bottom == GROUND_Y:
            self.vy = -16

    def update(self):
        self.vy += GRAVITY
        self.rect.y += self.vy
        if self.rect.bottom >= GROUND_Y:
            self.rect.bottom = GROUND_Y
            self.vy = 0
        if self.rect.bottom == GROUND_Y:
            self.step += 1
            self.image = self.frames[self.step // 8 % 2]
        else:
            self.image = self.frames[1]


class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = random.choice(obstacle_images)
        self.rect = self.image.get_rect(midbottom=(664, GROUND_Y))

    def update(self):
        self.rect.x -= speed
        if self.rect.right < 0:
            self.kill()


obstacle_images = [
    pygame.image.load("assets/images/spike_ball.png").convert_alpha(),
    pygame.image.load("assets/images/blob.png").convert_alpha(),
]
runner = Runner()
obstacles = pygame.sprite.Group()
speed = 6
pygame.time.set_timer(SPAWN, 1500)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            runner.jump()
        if event.type == SPAWN:
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))

    runner.update()
    obstacles.update()

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Tất cả bài học trong Luật chơi

Tự luyện tập: Playground Pygame