Quick answer: image.convert_alpha(). self.mask = pygame.mask.from_surface(self.image) on every animation frame change.

Two sprites visibly overlap. collide_mask returns None. Mask was generated from a non-alpha surface or wasn’t regenerated after frame change.

The Fix

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("p.png").convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect()

    def set_frame(self, frame_surface):
        self.image = frame_surface
        self.mask = pygame.mask.from_surface(self.image)

# Collision check
hit = pygame.sprite.collide_mask(player, enemy)
if hit:
    print("collide at", hit)

Mask must mirror current image. Cache masks once for static sprites; refresh on image change for animated.

Verifying

Sprites overlap: collide_mask returns offset tuple. Without convert_alpha: returns None even on overlap.

“convert_alpha. Recreate mask. Pixel collide.”

Related Issues

For Rect float warning, see Rect warning. For HiDPI text, see HiDPI.

Alpha + mask. Pixel-perfect.