Skip to main content
typos
Source Link
DMGregory
  • 141k
  • 23
  • 258
  • 401
  1. Resolve Penetration / Separation
    Given a pair of overlapping colliders, compute the smallest position change that gets them to no longer overlap. This is called the minimum separation vector / minimum separation distance. It's usually easy to compute for pairs of primitives like boxes/circles/spheres/capsules... but gets more complicated with polygons/meshes, especially if they can be concave...

    Once you have this vector, you can use it to resolve the overlap in two ways:

    • Shift the two colliders along this vector, one positively, one negatively. You can move each away by 1/2 the distance, or move one by the full vector and the other not at all (eg. if one is static/kinematic or vastly greater in mass) or any weighting you want in between.

      The advantage of this is that you can fully resolve simple collisions in a single step. And unlike the first two approaches, it doesn't stop objects before the collision, leaving a ghost buffer between the objects - you can run right up into kissing contact with a wall, from any distance. The disadvantage is that, like with undoing, resolving one pair of overlaps could cause or worsen another pair. Some collisions multi-way collisions aren't fully resolvable in one step this way, and can lead to unexpected jumps or jittering .

    • Apply an impulse to the bodies along this vector, so that their next movement step will move them apart. This roughly simulatesimulates elastic rebounding, and you can scale the magnitude of the impulse up or down to represent bouncier or squishier materials.

      The disadvantage of relying on impulses over shifts is that you might observe the penetration persisting for a frame or two before the objects manage to jostle their way apart. Or objects can accumulate so much velocity from these impulses that they're catapulted out of overlap at a silly-looking speed. But the advantage is that it's tolerant to complex multi-collisions that might not be fully resolvable in a single step, using only local pairwise interactions rather than needing a more complex global constraint solver tackling multi-way collisions.

    Many game physics engines use these two strategies in tandem, both applying a position correction to resolve the simple collisions immediately, and impulses to create rebounds and iteratively solve more complex pile-ups over multiple frames.

    One hazard to these approaches is that they don't take into account where the objects came from / how they got into this mess. If an object is moving at such great speed that in one step it passes 60% of the way through an obstacle, then the minimal vector that resolves the collision might be one that continues pushing it through the far side, contributing to "tunneling" bugs where objects seem to pass clear through solid walls. This also rears its head when walking along a flat ground made of multiple tiles with their own colliders, when you just straddle the corner of a new tile: the smallest vector to correct the overlap might be to push the player backward instead of up, making it feel like you're snagged on the corner where it should be seamless.

  2. Time of Impact
    An improvement to the method above is to take the velocities of the two bodies into account, and compute the moment within the timestep where these two objects first touched. Then we rewind them to that moment, apply any rebound impulses using the actual points/manifold of contact, and then allow them to continue from there.

  1. Resolve Penetration / Separation
    Given a pair of overlapping colliders, compute the smallest position change that gets them to no longer overlap. This is called the minimum separation vector / minimum separation distance. It's usually easy to compute for pairs of primitives like boxes/circles/spheres/capsules... but gets more complicated with polygons/meshes, especially if they can be concave...

    Once you have this vector, you can use it to resolve the overlap in two ways:

    • Shift the two colliders along this vector, one positively, one negatively. You can move each away by 1/2 the distance, or move one by the full vector and the other not at all (eg. if one is static/kinematic or vastly greater in mass) or any weighting you want in between.

      The advantage of this is that you can fully resolve simple collisions in a single step. And unlike the first two approaches, it doesn't stop objects before the collision, leaving a ghost buffer between the objects - you can run right up into kissing contact with a wall, from any distance. The disadvantage is that, like with undoing, resolving one pair of overlaps could cause or worsen another pair. Some collisions multi-way collisions aren't fully resolvable in one step this way, and can lead to unexpected jumps or jittering .

    • Apply an impulse to the bodies along this vector, so that their next movement step will move them apart. This roughly simulate elastic rebounding, and you can scale the magnitude of the impulse up or down to represent bouncier or squishier materials.

      The disadvantage of relying on impulses over shifts is that you might observe the penetration persisting for a frame or two before the objects manage to jostle their way apart. Or objects can accumulate so much velocity from these impulses that they're catapulted out of overlap at a silly-looking speed. But the advantage is that it's tolerant to complex multi-collisions that might not be fully resolvable in a single step, using only local pairwise interactions rather than needing a more complex global constraint solver tackling multi-way collisions.

    Many game physics engines use these two strategies in tandem, both applying a position correction to resolve the simple collisions immediately, and impulses to create rebounds and iteratively solve more complex pile-ups over multiple frames.

    One hazard to these approaches is that they don't take into account where the objects came from / how they got into this mess. If an object is moving at such great speed that in one step it passes 60% of the way through an obstacle, then the minimal vector that resolves the collision might be one that continues pushing it through the far side, contributing to "tunneling" bugs where objects seem to pass clear through solid walls. This also rears its head when walking along a flat ground made of multiple tiles with their own colliders, when you just straddle the corner of a new tile: the smallest vector to correct the overlap might be to push the player backward instead of up, making it feel like you're snagged on the corner where it should be seamless.

  2. Time of Impact
    An improvement to the method above is to take the velocities of the two bodies into account, and compute the moment within the timestep where these two objects first touched. Then we rewind them to that moment, apply any rebound impulses using the actual points/manifold of contact, and then allow them to continue from there.

  1. Resolve Penetration / Separation
    Given a pair of overlapping colliders, compute the smallest position change that gets them to no longer overlap. This is called the minimum separation vector / minimum separation distance. It's usually easy to compute for pairs of primitives like boxes/circles/spheres/capsules... but gets more complicated with polygons/meshes, especially if they can be concave...

    Once you have this vector, you can use it to resolve the overlap in two ways:

    • Shift the two colliders along this vector, one positively, one negatively. You can move each away by 1/2 the distance, or move one by the full vector and the other not at all (eg. if one is static/kinematic or vastly greater in mass) or any weighting you want in between.

      The advantage of this is that you can fully resolve simple collisions in a single step. And unlike the first two approaches, it doesn't stop objects before the collision, leaving a ghost buffer between the objects - you can run right up into kissing contact with a wall, from any distance. The disadvantage is that, like with undoing, resolving one pair of overlaps could cause or worsen another pair. Some multi-way collisions aren't fully resolvable in one step this way, and can lead to unexpected jumps or jittering .

    • Apply an impulse to the bodies along this vector, so that their next movement step will move them apart. This roughly simulates elastic rebounding, and you can scale the magnitude of the impulse up or down to represent bouncier or squishier materials.

      The disadvantage of relying on impulses over shifts is that you might observe the penetration persisting for a frame or two before the objects manage to jostle their way apart. Or objects can accumulate so much velocity from these impulses that they're catapulted out of overlap at a silly-looking speed. But the advantage is that it's tolerant to complex multi-collisions that might not be fully resolvable in a single step, using only local pairwise interactions rather than needing a more complex global constraint solver tackling multi-way collisions.

    Many game physics engines use these two strategies in tandem, both applying a position correction to resolve the simple collisions immediately, and impulses to create rebounds and iteratively solve more complex pile-ups over multiple frames.

    One hazard to these approaches is that they don't take into account where the objects came from / how they got into this mess. If an object is moving at such great speed that in one step it passes 60% of the way through an obstacle, then the minimal vector that resolves the collision might be one that continues pushing it through the far side, contributing to "tunneling" bugs where objects seem to pass clear through solid walls. This also rears its head when walking along a flat ground made of multiple tiles with their own colliders, when you just straddle the corner of a new tile: the smallest vector to correct the overlap might be to push the player backward instead of up, making it feel like you're snagged on the corner where it should be seamless.

  2. Time of Impact
    An improvement to the method above is to take the velocities of the two bodies into account, and compute the moment within the timestep where these two objects first touched. Then we rewind them to that moment, apply any rebound impulses using the actual points/manifold of contact, and then allow them to continue from there.

Source Link
DMGregory
  • 141k
  • 23
  • 258
  • 401

This problem of "I found a collision/overlap, now what do I do about it?" is called .

There are lots of different ways that games handle this, roughly in order of increasing complexity:

  1. Undo (as you described)
    Store the position before this movement integration step. If an overlap occurs, revert to this previous-good position.

This is very simple to implement, very efficient, but often feels rough in gameplay - once you get close to an obstacle, you'll tend to get stuck a small distance away, rather than moving all the way up to the surface or sliding along it. This is because a full move would overlap, so we cancel the whole thing. Worse, the exact distance at which this happens can change depending on your movement angle and where the obstacle lands in the rhythmic phase of your movement strides, creating visible inconsistencies in your gameplay.

This also gets more complicated when you have multiple moving objects that all need to avoid overlaps with each other - one could safely move into the empty space another left, detecting no overlap, but then the previous occupant could hit an overlap and get undone, creating a new overlap that wasn't present on your first collision detection pass, forcing you to re-evaluate at least some collision checks a second time.

  1. Sub-Stepping
    Instead of taking your full move all at once, divide it into steps, collision checking at each step. Move to the last non-overlapping spot. This is how Mario 64 handled Mario's movement, splitting the move into 4 so you can move 0, 25, 50, 75, or 100% of your expected movement, cutting the maximum position error proportionately.

This mitigates the more egregious problems with rewinding, but it's strictly only reducing them in degree. And it multiplies your collision-checking cost, so you might want to apply this only to the most visible objects like the player character, or collisions against static walls.

  1. Resolve Penetration / Separation
    Given a pair of overlapping colliders, compute the smallest position change that gets them to no longer overlap. This is called the minimum separation vector / minimum separation distance. It's usually easy to compute for pairs of primitives like boxes/circles/spheres/capsules... but gets more complicated with polygons/meshes, especially if they can be concave...

    Once you have this vector, you can use it to resolve the overlap in two ways:

    • Shift the two colliders along this vector, one positively, one negatively. You can move each away by 1/2 the distance, or move one by the full vector and the other not at all (eg. if one is static/kinematic or vastly greater in mass) or any weighting you want in between.

      The advantage of this is that you can fully resolve simple collisions in a single step. And unlike the first two approaches, it doesn't stop objects before the collision, leaving a ghost buffer between the objects - you can run right up into kissing contact with a wall, from any distance. The disadvantage is that, like with undoing, resolving one pair of overlaps could cause or worsen another pair. Some collisions multi-way collisions aren't fully resolvable in one step this way, and can lead to unexpected jumps or jittering .

    • Apply an impulse to the bodies along this vector, so that their next movement step will move them apart. This roughly simulate elastic rebounding, and you can scale the magnitude of the impulse up or down to represent bouncier or squishier materials.

      The disadvantage of relying on impulses over shifts is that you might observe the penetration persisting for a frame or two before the objects manage to jostle their way apart. Or objects can accumulate so much velocity from these impulses that they're catapulted out of overlap at a silly-looking speed. But the advantage is that it's tolerant to complex multi-collisions that might not be fully resolvable in a single step, using only local pairwise interactions rather than needing a more complex global constraint solver tackling multi-way collisions.

    Many game physics engines use these two strategies in tandem, both applying a position correction to resolve the simple collisions immediately, and impulses to create rebounds and iteratively solve more complex pile-ups over multiple frames.

    One hazard to these approaches is that they don't take into account where the objects came from / how they got into this mess. If an object is moving at such great speed that in one step it passes 60% of the way through an obstacle, then the minimal vector that resolves the collision might be one that continues pushing it through the far side, contributing to "tunneling" bugs where objects seem to pass clear through solid walls. This also rears its head when walking along a flat ground made of multiple tiles with their own colliders, when you just straddle the corner of a new tile: the smallest vector to correct the overlap might be to push the player backward instead of up, making it feel like you're snagged on the corner where it should be seamless.

  2. Time of Impact
    An improvement to the method above is to take the velocities of the two bodies into account, and compute the moment within the timestep where these two objects first touched. Then we rewind them to that moment, apply any rebound impulses using the actual points/manifold of contact, and then allow them to continue from there.

This solves many cases of tunneling (as long as the object doesn't hop fully past the obstacle in one step - we have to detect an overlap in order to run this routine), stopping/rebounding an object from the same side of the obstacle it came from. And it can give more physically accurate / plausible results.

But again, this does get more complicated as you add ingredients, like rotation or more complex collider shapes. Then the math to compute this moment of contact might get much more costly or require iterative approximation. And again, when you get three bodies or more colliding, resolving them all accurately can become intractable.

Some physics engines will also let you enable continuous collision detection for select objects, where instead of jumping all objects forward and checking for overlaps at the final position, you can sweep the objects through their whole travel - like a raycast/boxcast/spherecast - and find this moment of contact as part of the collision detection phase. This can completely solve tunnelling, but it is often much more expensive to compute.

This is by no means an exhaustive listing - games will use strategies beyond these, or mix elements of several strategies. But this covers some of the common themes you'll see in many games, and hopefully equip you with some conceptual frameworks and search terms you can use to find deeper documentation/Q&A/tutorials to build a solution that works for you.