# Pygame's sprite.collide_circle() missing several frames of head-on collision

I've spent hours trying to figure why my collision detection was so crappy, with sprites visibly ovellaping for several frames, when I noticed the culprit could be pygame's detection callback pygame.sprite.collide_circle().

I've stripped down the code and created a simple demo, and results were surprising: collide_circle() still returns False for several frames after its sibling collide_rect() correctly detects a collision and returns True.

Here is the code:

import pygame

RED   = (255,   0,   0)
GREEN = (  0, 255,   0)
BLUE  = (  0,   0, 255)
BLACK = (  0,   0,   0)
WHITE = (255, 255, 255)

SCREEN_SIZE = (800, 600)
FPS = 60
BG_COLOR = BLUE

class Ball(pygame.sprite.Sprite):
def __init__(self, color=WHITE, radius=10, position=[], velocity=[]):
super(Ball, self).__init__()

self.color = color
self.position = list(position) or [0, 0]
self.velocity = list(velocity) or [0, 0]

self.rect = self.image.get_rect()

def update(self, dt=1./FPS):
super(Ball, self).update()

for i in [0, 1]:
self.position[i] += self.velocity[i] * dt

self.velocity[i] *= -1

elif self.position[i] > self.bounds[i]:
self.position[i] = self.bounds[i]
self.velocity[i] *= -1

self.rect.center = self.position

pygame.init()

screen = pygame.display.set_mode(SCREEN_SIZE)
clock = pygame.time.Clock()

background = pygame.Surface(screen.get_size())
background.fill(BG_COLOR)
screen.blit(background, (0,0))

balls = pygame.sprite.Group()

done = False
while not done:
for event in pygame.event.get():
if (event.type == pygame.QUIT or
event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
done = True

balls.update()
if pygame.sprite.collide_rect(*balls):
collision = pygame.sprite.collide_circle(*balls)
print collision
if collision:
for ball in balls:
ball.velocity[0] *= -1

balls.clear(screen, background)
balls.draw(screen)
pygame.display.update()
clock.tick(FPS)

pygame.quit()


And the output:

False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
True
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False
False


That's 17 frames of overlap before collide_circle() realizes that hey, there's a collision there! Even at 60 FPS that's huge.

The balls are almost halfway through each other, and this behavior seems to be velocity independent: if I change the balls' speed or the FPS, the visual result (halfway overlap) remains, but for fewer frames.

So, my question is: is this a pygame bug? Or did I completely misunderstood how detection works?

• Not a complete answer, but did you consider doing an AABB/rectangle collision check first and then using collide_circle if there's a positive result? – ashes999 Aug 5 '14 at 21:11
• @ashes999 That was my initial idea, but the problem is in this demo the circles are colliding head-on horizontally, so results from collide_rect() and collide_circle() should be the same. All those False are not false positives, and collide_circle() should be able to detect them. – MestreLion Aug 6 '14 at 7:28
• @ashes999 also, note that I am using rectangle collision first! I'm only printing the cases that pass the test if pygame.sprite.collide_rect(*balls): – MestreLion Aug 6 '14 at 7:32
• did you test if collision is true by finding the distance between the circles and if the sum of there radii is more than the distance, they are colliding? – Serial Aug 13 '14 at 22:24
• @Serial yes, that's what I ended up doing myself, and it worked great, but isn't that what pygame.sprite.collide_circle() is supposed to do? – MestreLion Aug 14 '14 at 0:24

• I'm using 1.9.1release+dfsg-5, the one that ships with Ubuntu 12.04. It's weird that 1.9.2 isn't packaged yet in Debian/Ubuntu, considering it was released in 2012. And thanks a lot for the links! – MestreLion Nov 21 '14 at 5:40