Круглые хитбоксы
Часть раздела Спрайты и изображения путешествия по Pygame на Coddy. Урок 24 из 36.
Проверка пикселей точна, но точность не всегда кажется справедливой. Шип, задевший кончик крыла, считается попаданием. Во многих играх вместо этого проверяют фигуру поменьше и попроще — область попадания — и не считают попаданием случаи, когда объекты едва разминулись.
Для круглых объектов проверяйте круги. Задайте каждому спрайту radius, и pygame.sprite.collide_circle сочтёт столкновение попаданием, если расстояние между центрами меньше суммы двух радиусов:
self.radius = 24 # в Player.__init__
self.radius = 22 # в Ball.__init__
hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_circle)В этом случае расстояние между центрами равно 24 + 22 = 46 пикселям. Круги меньше изображений, поэтому их самые края могут задевать друг друга без попадания. Проверка кругов также обходится дёшево: одно расстояние, никаких пикселей.
Если не задан radius, collide_circle использует круг вокруг всего Rect, который больше самого Rect. Для спрайта прямоугольной формы ту же задачу решит прямоугольник Rect поменьше: self.rect.inflate(-16, -16) — это Rect на 16 пикселей уже и короче, с тем же центром.
Задание
Средне- Задай
Playerself.radius = 24, аBall—self.radius = 22. - Проверь с помощью
pygame.sprite.collide_circleвместоcollide_mask.
Попробуйте сами
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()
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Спрайты и изображения
1Загрузка изображений
Загрузить изображениеРазместить его с помощью RectПереместить изображениеЗамостить фонПрозрачные пиксели2Поворот, отражение, масштабирование
Вращение вокруг центраПовернись в направлении полётаИзменение масштаба изображенияВращение от исходного изображения5Пиксельно точные столкновения
Прямоугольники кажутся несправедливымиМаскиПиксельно точные спрайтыКруглые хитбоксы3Классы игровых объектов
Ваш первый классМетодыSelf — это объектСписок объектовОбъекты с изображениямиПодкласс6Анимация с помощью листов спрайтов
Разрезать лист спрайтовСчётчик кадровАнимация по времениОднократная анимация взрываПотренируйтесь самостоятельно: Песочница Pygame