Recently I've been working ony my game and so far I've got SAT collision detection-resolution working fine (I can detect two polygons intersecting and figure out the correct vector to push one out of another ('pushout' vectors))
However, I have run into a problem when applying the pushout vectors to other polygons. When a polygon gets into contact with 2 or more polygons, I end up with 2 or more pushout vectors, which need to be applied in the right order to get a realistic result (aka not glitching through the other polygons or getting stuck on corners that arent there)
Currently, I apply every push vector and each time I apply it I check if the polygon is still intersecting with the others it collided with, if so, I keep applying the rest of the vectors. If not, just stop applying as they are not colliding anymore.
The issue with this is that I need to apply the vectors in a specific order, not just in the other they are in the list. I dont know of a good solution to ordering them.
Heres my code (collider is the object that needs to have the pushout vectors applied to it) (otherColliders is a list of colliders that the collider is intersecting):
List<Vector2> pushoutVectors = getPushoutVectors(otherColliders);
foreach (Vector2 pushout in pushoutVectors)
{
collider.Transform.Position = pushout;
if (!collider.checkForIntersecting(otherColliders))
break;
}
The picture below shows my current issue. Is there a solution to getting vector (-1, 0) before (0, 1)?
CodePudding user response:
Alright, solved it!
Incase anyone is interested, the solution was to sort based on distance from the centre of each collider. Do not sort from the origin point or similar - sort by the distance between the centre of both colliders in ASCENDING order. This ensures that the pushout vectors are applied properly and no clipping or getting stuck occurs.
(oh and also to whoever downvoted this please tell me why so I can edit the question as necessary)
sample code:
public struct Hit
{
public Collider Me;
public Collider Other;
public Vector2 Pushout;
public float getCenteredDistanceFromOtherSquared()
{
return Vector2.DistanceSquared(Me.getWorldBounds().Center, Other.getWorldBounds().Center);
}
}
List<Hit> hits = getHits(otherColliders);
// note: this is a long function name for the sake of being clear.
// it returns the distance between the 'collider' and the 'other' collider in the collision
// its squared simply because we just need to order by size not get the actual size, so its just to prevent use of a performance-costly sqrt function
List<Hit> sortedhits = hits.OrderBy(x => x.getCenteredDistanceFromOtherSquared()).ToList();
foreach (Hit hit in sortedhits)
{
// apply pushout
collider.Transform.Position = hit.Pushout;
// check if we're still colliding with any other colliders
// if we aren't, stop applying hits
// if we are, keep applying hits
// this is to prevent getting stuck on edges and such
if (!collider.checkForIntersecting(otherColliders))
break;
}