Quick answer: Use pygame.sprite.LayeredUpdates. Set sprite._layer = sprite.rect.bottom; call change_layer on move.

Top-down RPG. Trees draw above player when player is north of them. Wrong order. Plain Group doesn't sort.

The Fix

group = pygame.sprite.LayeredUpdates()

class Tree(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.image.load("tree.png")
        self.rect = self.image.get_rect(midbottom=(x, y))
        self._layer = self.rect.bottom

# Per frame after movement
group.change_layer(player, player.rect.bottom)
group.draw(screen)

LayeredUpdates draws back-to-front by _layer. Update the field as sprites move.

Verifying

Player walks behind trees that are south. Without LayeredUpdates: arbitrary.

“LayeredUpdates. Y-sort right.”

Related Issues

For collide_mask, see collide_mask. For dirty rects, see flip update.

LayeredUpdates. Y-sort.