Monday, September 24, 2018

python - Collision Resolution of Axis-Aligned Bounding Boxes that Change Size


I am developing an action platformer in Python, with Pygame. That said, my question is a general one about collision resolution strategies.



I use an axis-aligned bounding box for the purposes of collision detection. The bounding box changes sizes depending on the sprite's action and the frame of the action's animation.


When I update my sprite's position, I first update the y-coordinate, check for and resolve collision in the y-direction, then do the same for the x-coordinate. When I resolve collision, I simply move the bounding rect's sides to align flush with the appropriate walls.


Because the bounding rect changes sizes throughout my animations, I am noticing buggy behavior in certain situations when the frame moves from a smaller one to a larger one. The change of frame results in the sprite intersecting a wall and his position is resolved such that he falls off the map.


Here is a diagram illustrating the problem:


enter image description here


It doesn't matter whether I resolve in the x-direction or the y-direction first. They result in reciprocal buggy behavior when the next frame is wider or taller, respectively.


My question concerns general collision resolution strategies for axis-aligned bounding boxes that change size and shape. What are the best algorithms for collision resolution that avoid this issue?


Here are some of the functions and values I have access to:



  • colliderect -- tests if two rectangles collide


  • collidepoint -- boolean that tests if a point collides with a rectangle

  • rect.topleft, rect.topright, rect.bottomleft, rect.bottomright, rect.center, rect.centerx, rect.centery -- various points on the rectangles

  • rect.left, rect.right, rect.top, rect.bottom -- values for the sides of the rects

  • various vectors

  • in short, the usual stuff


Apologies if this question is a dupe. I imagine it is a pretty common one, though I couldn't find anything that helped me specifically.



Answer



In brief there are two ways of doing this. Both are relatively fast and simple to run.


Method 1

If the AABB (axis aligned bounding box) changes every frame because of animations, then you can simply wait until after the sprite has been moved and the next frame of the animation has played before resolving the collisions


def MainLoop():
#Update the position
rect.center = rect.center + velocity

#I don't know how you are doing your animations, but play the next frame here
Animate.PlayNextFrame()

#Now you want to check for collisions as normal now that everything has moved in the frame we can check for collisions once
CheckCollisions()


This means that the collision detection occurs only once animation and the movement has occurred. This prevents the need to do collision detection more than once per frame and takes the animation into account.


Method 2
Make a dummy aabb for collision detection that follows the main character which has a fixed size. This will occasionally result in some minor intersection between the character and the wall but in most cases it looks fine.
Sprite intersection isn't a big deal
This is also relatively easy to implement and very fast to run.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...