Skip to content
Learn Netverks
-2

How to separate a body colliding with two (or more) others given their overlap

asked 8 hours ago by @qa-wad9ulhofjsdwrqfhfij 0 rep · 54 views

javascript 2d collision detection game development game physics

I am programming a top-down game where the player is a circle and there are circular and polygonal obstacles that the player can collide with. I am using a Separating Axis Theorem library to help with my collisions and this is the basic method (pseudocode):

for(let obstacle of obstacles){
   if(collides(obstacle, player)){
      const overlap = getOverlap(player, obstacle);
      player.x -= overlap.x;
      player.y -= overlap.y;
   }
}

This works great when the player collides with one obstacle, but with two or more the player jitters about. I think because they aren't fully removed from the obstacle on the first server tick, and only once they stop inputting movement do they eventually clip out after a few ticks. I've also tried adding all of the overlap up and then applying it once at the end, but that caused even more jittering (pseudocode):

const totalOverlap =  { x: 0, y: 0 };

for(let obstacle of obstacles){
   if(collides(obstacle, player)){
      const overlap = getOverlap(player, obstacle);
      totalOverlap.x += overlap.x;
      totalOverlap.y += overlap.y;
   }
}

player.x -= totalOverlap.x;
player.y -= totalOverlap.y;

Let me know how I should be doing this instead! Thanks in advance.

Comments on this question (0)

Use comments to ask for clarification — answers go in the answer box below.

Log in to comment on this question.

0

I usually solve this backwards by not letting it happen. I move the player until they hit something. Often the player is moving slowly enough (per frame) that I can just do this: test-move entire movement, if overlapping anything return to starting position.

For more precise movement, if you have access to a circlecast fire it (in the direction the player is moving as far as they want to move). It should either tell you "safe" or "hit something after X distance moved". Then you just move the player there (you may have to compute the fraction of the distance to get the partial movement vector).

Alternately you can pick a delta, like 0.1, and move in small steps: [loop until move used up] { move 0.1 or remaining amount, if overlap go back to last good spot and quit }. To get really fancy, could use a binary search (move 1/2, if overlap try 1/4; if no overlap try 3/4th, repeat). But I've found the "small steps of 0.1" method is plenty fast, and it also avoids going completely through small objects or corners if you've moving quickly.

And a note, I think your single-collision code is moving too far backwards and possibly in the wrong direction. Subtracting either x or y overlap will unoverlap you. Imagine the blue circle moves forward and hit just A. Subtracting the y overlap will fix it. Also moving it in the x direction makes it slide around that red cube (which is a good idea, but usually works better when specifically planned). And you're also changing how far they moved -- you could even be giving them a little extra free movement coming from some angles. My point is that the reverse "don't let it overlap" method also solves that problem.

Cameron Price · 0 rep · 8 hours ago

Your answer