Quick answer: Use the closest-point method: clamp circle center to rect bounds, compute distance to clamped point, compare to radius.

A ball game uses circle collision against rect walls. Near rect corners, collision fires when the ball is visibly outside — pygame.Rect collidepoint doesn’t handle the circular shape.

Closest Point Method

def circle_rect_collide(cx, cy, radius, rect):
    closest_x = max(rect.left, min(cx, rect.right))
    closest_y = max(rect.top, min(cy, rect.bottom))
    dx = cx - closest_x
    dy = cy - closest_y
    return dx*dx + dy*dy < radius*radius

Squared distance avoids sqrt. Clamp gives the closest point on the rect to the circle center; if that point is within radius, they collide.

Why Rect Methods Aren't Enough

pygame.Rect.colliderect only handles rect-rect. Treating circle as bounding rect produces false positives at corners (rect overlaps but circle doesn’t reach into the corner).

For Sprite Group Checks

def collide_circle_rect(circle_sprite, rect_sprite):
    return circle_rect_collide(circle_sprite.rect.centerx, circle_sprite.rect.centery, circle_sprite.radius, rect_sprite.rect)

pygame.sprite.spritecollide(player, walls, False, collided=collide_circle_rect)

Pass as the collided argument to spritecollide.

Verifying

Move circle near corners. Collision fires only when circle visibly overlaps. No phantom corner collisions.

“Closest-point on rect is the classic trick. One clamp, one comparison, perfect circle-rect.”

For circle-circle or polygon-polygon, see SAT (separating axis theorem) — same idea, different math.