How would I prevent two masks from overlapping each other when a collision is detected? I know how to detect mask collisions but I can't wrap my head around actually preventing them from colliding. I'm pretty sure the solution has to do something with mask.overlap_area
, but when I try using the code provided, It doesn't seem to work at all:
example gif (the blue dot is [dx, dy] )
import pygame
import sprites
SCREEN_HEIGHT, SCREEN_WIDTH = 800, 800
running = True
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
player = sprites.Block((100, 100))
block2 = sprites.Block((100, 100))
blocks = pygame.sprite.Group(block2)
block2.rect.topleft = 150, 150
while running:
events = pygame.event.get()
screen.fill((100, 100, 100))
for event in events:
if event.type == pygame.QUIT:
running = False
player.move(screen.get_rect())
screen.blit(player.image, player.rect)
for block in blocks:
offset = (player.rect.x - block.rect.x, player.rect.y - block.rect.y)
dx = player.mask.overlap_area(block.mask, (offset[0] + 1, offset[1])) - \
player.mask.overlap_area(block.mask, (offset[0] - 1, offset[1]))
dy = player.mask.overlap_area(block.mask, (offset[0], offset[1] + 1)) - \
player.mask.overlap_area(block.mask, (offset[0], offset[1] - 1))
screen.blit(block.image, block.rect)
print(dx, dy)
pygame.draw.circle(screen, (0, 0, 255), (dx + block.rect.x, dy + block.rect.y), 5)
clock.tick(144)
pygame.display.flip()
Do I just have the wrong idea?
I think the issue is that your program is allowing the overlap in the first place. Once they're colliding you can't do anything.
Before moving the object, check that the destination location is not already occupied by doing a "future collision" check. If there's going to be a collision, then either don't allow the movement at all, or handle it in some nicer way.
If you know the direction of movement - say the player pushed ā, and is moving left. The code can easily move the player as far left as possible, to the point just before colliding.
This way you never have to deal with objects atop each other.
It's not really clear to me what approach the program is taking. The API pygame.mask.overlap_area() returns the number of bits overlapping. The code is calculating the collision normal, not trying to prevent or undo the overlap. Maybe it can move each object by the inverse of this direction, or suchlike.