Menu
CoddyTech

Zones de collision circulaires

Fait partie de la section Sprites et images du Journey Pygame de Coddy. Leçon 24 sur 36.

Un test de pixels est exact, mais ce qui est exact ne semble pas toujours juste. Une pointe qui effleure l’extrémité d’une aile compte comme un impact. À la place, de nombreux jeux testent une forme plus petite et plus simple, une zone de collision, et ignorent les frôlements.

Pour les objets ronds, testez des cercles. Attribuez un radius à chaque sprite, et pygame.sprite.collide_circle considère qu’il y a un impact lorsque la distance entre les centres est inférieure à la somme des deux rayons :

self.radius = 24  # dans Player.__init__
self.radius = 22  # dans Ball.__init__

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

Ici, cela représente 24 + 22 = 46 pixels entre les centres. Les cercles sont plus petits que les images, leurs bords peuvent donc s’effleurer sans provoquer d’impact. Un test par cercle est également peu coûteux : une seule distance, aucun pixel.

Sans radius, collide_circle utilise un cercle autour du Rect entier, plus grand que le Rect lui-même. Pour un sprite de forme rectangulaire, un Rect plus petit fait le même travail : self.rect.inflate(-16, -16) est un Rect 16 pixels moins large et moins haut, avec le même centre.

challenge icon

Défi

Moyen
  1. Donne à Player self.radius = 24 et à Ball self.radius = 22.
  2. Teste avec pygame.sprite.collide_circle au lieu de collide_mask.

Essayez vous-même

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()
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Sprites et images

Entraînez-vous par vous-même : Playground Pygame