Menu
CoddyTech

Sprite chính xác đến từng pixel

Thuộc phần Sprite và hình ảnh trong hành trình Pygame của Coddy. Bài học 24 trên 39.

Sprite cũng có thể dùng mask, và pygame tự xử lý độ lệch cho bạn. Tạo self.mask cho mỗi sprite, chỉ tạo một lần trong __init__:

self.mask = pygame.mask.from_surface(self.image)

Sau đó truyền pygame.sprite.collide_mask làm đối số thứ tư cho spritecollide:

hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_mask)

Đối số thứ tư là phép kiểm tra dùng cho từng cặp. Nếu không có đối số này, phép kiểm tra sẽ dùng Rect. Khi dùng collide_mask, phép kiểm tra sẽ dùng mask, được đặt theo Rect của mỗi sprite. groupcollide cũng nhận đối số thứ năm tương tự.

Phép kiểm tra mask tốn chi phí hơn phép kiểm tra Rect, nhưng overlap chỉ so sánh các pixel nằm trong vùng hai Rect chồng lên nhau, nên các cặp ở xa nhau sẽ được xử lý nhanh. Với vài chục sprite, bạn sẽ không nhận thấy chi phí này. Nếu sprite không có mask, collide_mask sẽ tạo mask từ hình ảnh của sprite trong mỗi lần kiểm tra, vì vậy hãy đặt mask trong __init__.

challenge icon

Thử thách

Trung bình

Chỉ tính là va chạm khi các hình chạm nhau.

  1. Tạo self.mask cho Player và Ball từ self.image.
  2. Truyền pygame.sprite.collide_mask vào spritecollide.

Nhấn Chơi: Hit! chỉ xuất hiện khi các hình chạm nhau. Sau đó nhấn Kiểm tra.

Tự làm thử

import pygame

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Spike Field")
clock = pygame.time.Clock()

ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
ball_image = pygame.image.load("assets/images/spike_ball.png").convert_alpha()
font = pygame.font.Font(None, 40)


class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = ship_image
        self.rect = self.image.get_rect(topleft=(420, 320))

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= 4
        if keys[pygame.K_RIGHT]:
            self.rect.x += 4
        if keys[pygame.K_UP]:
            self.rect.y -= 4
        if keys[pygame.K_DOWN]:
            self.rect.y += 4


class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = ball_image
        self.rect = self.image.get_rect(center=(x, y))


player = Player()
balls = pygame.sprite.Group(Ball(160, 240), Ball(320, 240), Ball(480, 240))

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    player.update()
    hits = pygame.sprite.spritecollide(player, balls, False)

    screen.fill((20, 22, 40))
    balls.draw(screen)
    screen.blit(player.image, player.rect)
    if hits:
        text = font.render("Hit!", True, (240, 240, 240))
        screen.blit(text, (10, 10))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Tất cả bài học trong Sprite và hình ảnh

Tự luyện tập: Playground Pygame