Vùng va chạm hình tròn
Thuộc phần Sprite và hình ảnh trong hành trình Pygame của Coddy. Bài học 25 trên 39.
Kiểm tra từng pixel rất chính xác, nhưng chính xác không phải lúc nào cũng tạo cảm giác công bằng. Một chiếc gai sượt qua đầu cánh cũng được tính là va chạm. Thay vào đó, nhiều trò chơi kiểm tra một hình dạng nhỏ hơn, đơn giản hơn gọi là vùng va chạm, để những pha suýt trúng không bị tính.
Với các vật thể tròn, hãy kiểm tra bằng hình tròn. Gán cho mỗi sprite một radius, rồi pygame.sprite.collide_circle tính là va chạm khi khoảng cách giữa hai tâm nhỏ hơn tổng hai bán kính:
self.radius = 24 # trong Player.__init__
self.radius = 22 # trong Ball.__init__
hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_circle)Ở đây, khoảng cách giữa hai tâm là 24 + 22 = 46 pixel. Các hình tròn nhỏ hơn hình ảnh, nên các cạnh ngoài cùng có thể sượt qua nhau mà không tính là va chạm. Kiểm tra bằng hình tròn cũng rất nhẹ: chỉ cần tính một khoảng cách, không cần xét pixel.
Nếu không có radius, collide_circle dùng một hình tròn bao quanh toàn bộ Rect, lớn hơn chính Rect. Với sprite hình hộp, Rect nhỏ hơn cũng cho kết quả tương tự: self.rect.inflate(-16, -16) là Rect hẹp hơn và ngắn hơn 16 pixel, nhưng vẫn giữ nguyên tâm.
Thử thách
Trung bìnhKiểm tra va chạm bằng hình tròn thay vì mặt nạ.
- Gán cho
Playerself.radius = 24và choBallself.radius = 22. - Kiểm tra bằng
pygame.sprite.collide_circlethay vìcollide_mask.
Nhấn Chơi: đầu cánh có thể sượt qua gai nhọn mà Hit! không xuất hiện. 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))
self.mask = pygame.mask.from_surface(self.image)
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))
self.mask = pygame.mask.from_surface(self.image)
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, pygame.sprite.collide_mask)
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()
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Sprite và hình ảnh
5Va chạm chính xác đến từng pixel
Hình chữ nhật thật bất côngMặt nạSprite chính xác đến từng pixelVùng va chạm hình tròn3Lớp cho đối tượng trong trò chơi
Lớp đầu tiên của bạnPhương thứcSelf là đối tượngDanh sách đối tượngĐối tượng có hình ảnhDanh sách kẻ địchLớp con6Hoạt ảnh từ sprite sheet
Cắt sprite sheetBộ đếm khung hìnhTạo hoạt ảnh theo thời gianHiệu ứng nổ chỉ chạy một lầnTự luyện tập: Playground Pygame