0
\$\begingroup\$

I have a 2-part question:

1: I have 2 rectangles, A and B. B is a wall and A is moving. My simple logic here is every time A moves, it moves based on some (x,y) offset and then checks if it collided with something. If it is colliding with something, roll back bit by bit in the opposite direction until it is not colliding anymore.

The problem here is if A moves in large chunks, it might skip over B entirely.

The intended behavior is to find out where A should be when it first touched one of B's faces and then roll back to that point and apply collision resolution.

2: What if B is moving as well?

What I'm currently doing to side step this issue is to create large enough collision boxes and make sure moving objects do not exceed some maximum. This approach seems like it will be limiting in the future.

I assume there is a mathematical way to solve this but I wasn't able to find any answers from my searches. Any tips/suggestions are greatly appreciated.

Thanks!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Try searching for key phrases like "minimum translation vector" or "time of collision / impact / first contact" (each ways of calculating what you call the "rollback point"), "tunnelling" (the problem of skipping over narrow collisions with fast objects), and "continuous collision detection / swept collision detection" (strategies to detect & stop tunnelling without making the colliders too big / the speeds & timesteps too small). I think all the answers you need are already out there, you might just be missing the usual vocabulary for describing the situation to find them. \$\endgroup\$
    – DMGregory
    Commented Feb 14, 2019 at 12:41

2 Answers 2

1
\$\begingroup\$

What you're looking for is called swept or dynamic AABB collision detection.

When dealing with a static and a dynamic (moving) object, you need to take the velocity of the latter in both x and y axes and divide the distance from the static rectangle on the axes by them. Then choose the one that's lower and it should be the time it takes for the rectangle to reach the static one:

if moving.vel.x < 0 then
    distX = static.right - moving.left
else
    distX = static.left - moving.right
endif

if moving.vel.y < 0 then
    distY = static.bottom - moving.top
else
    distY = static.top - moving.bottom
endif

timeX = distX / moving.vel.x
timeY = distY / moving.vel.y

collisionTime = min(timeX, timeY)

moving.move(collisionTime * moving.vel.x, collisionTime * moving.vel.y)

For the dynamic-dynamic case you can use the same thing. You need to realize, that if we were to look at the collision from one of the moving rectangles' local coordinates, then we see that rectangle as a static one (it always stays in (0,0)), and the other is moving a lot faster. So replace the velocity in the pseudo code above with moving1.vel - moving2.vel where moving1 will act as the dynamic rectangle and moving2 is the static one

\$\endgroup\$
2
  • \$\begingroup\$ I ran into a problem: I move diagonally up-left and hit a the middle of a wall. The algorithm will do static.right - moving.left because I'm moving left, and static.bottom - moving.top because I'm moving up. The player is hitting the wall from below so the collision is happening more on the bottom face of the wall than the right face. But the player is hitting the middle of the bottom face of the wall. So the algorithm thinks the collision on the x axis happened earlier, since static.right - moving.left will be a large number (since I'm hitting it from the middle)...opposed to the y-axis \$\endgroup\$
    – errandel
    Commented Mar 3, 2019 at 8:31
  • 1
    \$\begingroup\$ collisionTime = min(timeX, timeY) is wrong, as BugSquasher mentioned. Unless you already know they collide you actually need to find both the start and end times of the intersection on the X and Y axes, and if those two intervals overlap then take collisionTime = max(timeX, timeY), which is the start of the overlap. \$\endgroup\$ Commented May 2, 2020 at 2:26
0
\$\begingroup\$

You have at least 3 basic options.

1) Overlap check (suffers from tunneling) 2) Sweep test (needs collision extraction) 3) Intercept test (finds exact intercept time)

Which one is right for you depends on a few things. One is how often you want to update your collision detection. Using 1) with high logic rates or low velocities is often acceptable. 2) works well for objects with static acceleration and 3) works best of the three but is most expensive computationally

Balint's answer is incomplete. While getting the intercept time on each axis is fine, and necessary for 3), it does not actually indicate the time of collision, as the other axis has to be overlapping during the collision time for it to be an actual collision.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .