Hello,
I'm currently programming a very simple physic engin but recently i've come to a problem i've put too many hours on.
I'm using the separating axis theorem to detect collision between 2 shape (usually a rotating rectangle and a static polygon).
I am calculating the minimum translation vector to resolve collisions.
Everything seems to be working except for one thing:
If an actor (my rotating rectangle) is touching a slope (the static polygon) by only one pixel, the calculated MTV will be (-1,0) insteed of the expected (-1,-1). For everything else, it's working fine.
For the visuals, here is an image.
I'm handling my physic this way: Horizontal first then vertical. Since this is an horizontal collision i would used the MTV (-1, -1) and move the actor Y position up by 1 pixel. The actor X is untouched at this point.
But since the returned MTV is (-1, 0), i can't move the actor up the slope the very first time he touche it.
Here is some of my code. If the lisibility is not acceptable, i will be glade to answers yours questions.
//////////////////////////////////////////////////////////////////////////
//Try to find if an Axis can disprove collision.
bool CMath::Sat(CPolygon *_a, CPolygon *_b, CVector &_mtv, int &_solid)
{
float overlap = 1000; //Large value.
CVector smallest(0,0); //MTV (Minimum translation vector). This is the resolving vector.
int numberofcollision = 0;
//For polygon A...
for (int i = 0; i < _a->n; i++)
{
// Get the direction vector
CVector axis = _a->edges[i].dir;
// Get the normal of the vector (90 degrees)
axis = Perp(axis);
// Find the projection of a and b onto axis
CVector p1 = Project(_a,axis), p2 = Project(_b,axis);
// If they do not overlap, then no collision
float o = 1000;
if (!Overlap(p1,p2, o))
return false;
//Update the MTV
else
{
if(o < overlap)
{
overlap = o;
smallest = axis;
}
}
}
// repeat for b
for (int i = 0; i < _b->n; i++)
{
CVector axis = _b->edges[i].dir;
axis = Perp(axis);
CVector p1 = Project(_a,axis), p2 = Project(_b,axis);
float o = 1000;
if (!Overlap(p1,p2, o))
return false;
else
{
if(o < overlap)
{
overlap = o;
smallest = axis;
}
}
}
//No Axis can prove the Polygon is not colliding, so it must be colliding.
//Calculate the MTV;
_solid = smallest.x == 0 || smallest.y == 0;
smallest = Normalize(smallest);
_mtv.x = smallest.x * (overlap + 1); //if we are touching something that is not a slope, always push the actor by 1 pixel.
_mtv.y = smallest.y * (overlap + 1);
return true;
}
//////////////////////////////////////////////////////////////////////////
//
bool CMath::Overlap(CVector _p1, CVector _p2, float &_overlap)
{
if (Contains(_p1,_p2, _overlap) ) return true;
return false;
}
//////////////////////////////////////////////////////////////////////////
//
bool CMath::Contains(CVector _range1, CVector _range2, float &_overlap)
{
_overlap = abs(_range1.y - _range2.x);
return (_range1.y >= _range2.x && _range1.x <= _range2.y);
}
Thank you very much for your time. I will continue searching on my ends and will post the solution if i finds it myself.
Ps. I appologize if my english is bad.