Hitboxes circulares
Parte de la sección Sprites e imágenes del Journey de Pygame de Coddy. Lección 24 de 36.
Una prueba píxel a píxel es exacta, pero lo exacto no siempre parece justo. Si una espiga roza la punta de un ala, cuenta como impacto. En muchos juegos se prueba en su lugar con una forma más pequeña y sencilla, una caja de colisión, y se dejan pasar los fallos por poco.
Para los objetos redondos, prueba con círculos. Dale a cada sprite un radius, y pygame.sprite.collide_circle lo considera un impacto cuando los centros están más cerca que la suma de los dos radios:
self.radius = 24 # en Player.__init__
self.radius = 22 # en Ball.__init__
hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_circle)En este caso, son 24 + 22 = 46 píxeles entre los centros. Los círculos son más pequeños que las imágenes, así que los bordes pueden rozarse sin que haya impacto. Una prueba con círculos también es económica: una distancia, ningún píxel.
Sin un radius, collide_circle usa un círculo alrededor de todo el Rect, más grande que el propio Rect. Para un sprite con forma de caja, un Rect más pequeño hace lo mismo: self.rect.inflate(-16, -16) es el Rect 16 píxeles más estrecho y bajo, con el mismo centro.
Desafío
Intermedio- Asigna a
Playerself.radius = 24y aBallself.radius = 22. - Prueba con
pygame.sprite.collide_circleen lugar decollide_mask.
Pruébalo tú mismo
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()
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Sprites e imágenes
1Cargar imágenes
Cargar una imagenColocarla con un rectánguloMover la imagenRepetir un fondo en mosaicoPíxeles transparentes2Girar, voltear y escalar
Girar alrededor del centroApuntar en la dirección del vueloEscalar una imagenGirar desde la imagen original5Colisiones precisas a nivel de píxel
Los rectángulos parecen injustosMáscarasSprites precisos a nivel de píxelHitboxes circulares3Clases para objetos del juego
Tu primera claseMétodosSelf es el objetoUna lista de objetosObjetos con imágenesUna subclase6Animación con hojas de sprites
Recortar una hoja de spritesUn contador de fotogramasAnimar con el tiempoUna explosión de una sola vezPractica por tu cuenta: Playground de Pygame