1
\$\begingroup\$

I would like to know a better way of collision resolution than I am currently doing. My current collision system stores the current positions and previous positions of each object. When an object collides with another it sets the current positions to the previous positions.

This would work fine if objects could only move in four directions, but when they can move in more than four directions the system doesn't work. For example if you are moving an object_A up and right and it collides with and object_B above it, the object_A stops moving even if still going up and right. In most 2d games however if this scenario happened the object_A would stop moving up but continue to move right. This is the kind of collision resolution that I would like to implement. I don't need anymore complicated physics right now this will do.

I'm just using rectangles so that would be the only shape I need to worry about.

\$\endgroup\$
1
\$\begingroup\$

Here are two options you could consider; an easy one and one that you'd find in commercial games.

Solution 1: Separate your movement axes

If your objects are all rectangles (assumed to be axis-aligned), you could consider horizontal and vertical motion separately. This means your motion procedure will be updated to:

// Horizontal movement
x_previous = x;
x += velocity_x;
if (colliding()) { x = x_previous; }

// Vertical movement
y_previous = y;
y += velocity_y;
if (colliding()) { y = y_previous; }

Note that this will only work assuming all-rectangular geometry and small movement steps. For example, your objects would not be able to through an upward corridor smoothly as they will - as a matter of speaking - alternate between banging into the ground and into the roof.

An additional disadvantage of your technique is that objects will not be able to stop right against the wall. For example, if their horizontal velocity is 10 and their is a wall nearby, they will end up with a gap of 0 to 9 units between them and the wall.


Solution 2: Calculate collision positions and normals

The behavior you are trying to achieve seems to be "wall-sliding". This means, if you walk into a wall, you will slide along it depending on your movement direction.

The way this is achieved in commercial games, is by calculating more information on the collision. In your case, you just "calculate" the answer to the question "Am I colliding or not?". Information that is required to solve your problem in a more elegant manner is "At what position did I collide?" and "What is the normal of the surface I collided with?". This information can be obtained for example by raycasting your object's bounding box against collision geometry (e.g. by line-raycasting the configuration space obstacle (CSO)).

Using this information, you can resolve you collisions in the following way:

  1. Calculate your motion_vector as (velocity_x, velocity_y)
  2. Perform a ray-cast along ths motion vector to obtain collision_position and collision_normal
  3. Move your object to the collision_position (or slightly before it) so that it doesn't intersect with other objects anymore
  4. Calculate your new motion_vector, as your current motion_vector minus the component of your motion_vector parallel to the collision_normal
  5. Shorten the length of your motion_vector by the distance you've already moved
  6. Repeat steps 2 through 5 until the object managed to move the full length of the motion_vector

While this solution is more complicated, it will resolve the two primary problems with the simple approach (objects leaving a gap inbetween them upon colliding and not being able to cope with non-rectangular bounding boxes).


In summary: the easiest way to solve the problem for your use-case is to separate your movement axes. The way it is solved in commercial games involves calculating more information such as the collision position and the collision normal.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.