Quick answer: Use pygame.FRect (Pygame 2.1.3+) for float-precise collision. Keep simulation positions as floats; convert to int only at blit time.
Two sprites approach. They should overlap by a fraction of a pixel. Rect.colliderect returns False because integer truncation produced a one-pixel gap. FRect carries the fractional position.
The Symptom
Edge collisions miss when objects are very close but not overlapping by full pixels. Or random misses on diagonals where one axis snaps to the same int and the other doesn’t.
The Fix
import pygame
class Player:
def __init__(self):
self.x = 100.5
self.y = 50.25
self.rect = pygame.FRect(self.x, self.y, 32, 32)
def update(self, dt):
self.x += self.vx * dt
self.y += self.vy * dt
self.rect.x = self.x
self.rect.y = self.y
def draw(self, screen, image):
screen.blit(image, (int(self.x), int(self.y)))
# Collision works on FRect with full float precision
if player.rect.colliderect(enemy.rect):
...
FRect carries floats; colliderect uses them. blit takes ints (lossy but only visual).
For Older Pygame
If on Pygame < 2.1.3, store positions as floats separately and rebuild Rect each frame:
self.rect.x = int(self.x)
self.rect.y = int(self.y)
Some sub-pixel collisions still miss, but the bigger error (10+ frames out of sync) is gone.
Verifying
Two sprites placed 0.4 pixels apart with FRect: collide. With Rect (and int truncation): may not. Visual test by drawing both rects to confirm overlap.
“FRect for collision. int for draw. Sub-pixel hits register.”
Related Issues
For sprite group order, see draw order. For text edges, see text edges.
FRect. Sub-pixel honest.