namespace SuperTux
{
+static const float DELTA = .0001;
+
bool
Collision::rectangle_rectangle(CollisionHit& hit, const Rectangle& r1,
- const Rectangle& r2)
+ const Vector& movement, const Rectangle& r2)
{
if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
return false;
if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
return false;
-
- hit.depth = r1.p2.x - r2.p1.x;
- hit.normal.x = -1;
- hit.normal.y = 0;
- float px2 = r2.p2.x - r1.p1.x;
- if(px2 < hit.depth) {
- hit.depth = px2;
+ if(movement.x > DELTA) {
+ hit.depth = r1.p2.x - r2.p1.x;
+ hit.time = hit.depth / movement.x;
+ hit.normal.x = -1;
+ hit.normal.y = 0;
+ } else if(movement.x < -DELTA) {
+ hit.depth = r2.p2.x - r1.p1.x;
+ hit.time = hit.depth / -movement.x;
hit.normal.x = 1;
hit.normal.y = 0;
+ } else {
+ if(movement.y > -DELTA && movement.y < DELTA) {
+ return false;
+ }
+ hit.time = FLT_MAX;
}
- float py1 = r1.p2.y - r2.p1.y;
- if(py1 < hit.depth) {
- hit.depth = py1;
- hit.normal.x = 0;
- hit.normal.y = -1;
- }
-
- float py2 = r2.p2.y - r1.p1.y;
- if(py2 < hit.depth) {
- hit.depth = py2;
- hit.normal.x = 0;
- hit.normal.y = 1;
+ if(movement.y > DELTA) {
+ float ydepth = r1.p2.y - r2.p1.y;
+ float yt = ydepth / movement.y;
+ if(yt < hit.time) {
+ hit.depth = ydepth;
+ hit.time = yt;
+ hit.normal.x = 0;
+ hit.normal.y = -1;
+ }
+ } else if(movement.y < -DELTA) {
+ float ydepth = r2.p2.y - r1.p1.y;
+ float yt = ydepth / -movement.y;
+ if(yt < hit.time) {
+ hit.depth = ydepth;
+ hit.time = yt;
+ hit.normal.x = 0;
+ hit.normal.y = 1;
+ }
}
return true;
bool
Collision::rectangle_aatriangle(CollisionHit& hit, const Rectangle& rect,
- const AATriangle& triangle)
+ const Vector& movement, const AATriangle& triangle)
{
- if(!rectangle_rectangle(hit, rect, (const Rectangle&) triangle))
+ if(!rectangle_rectangle(hit, rect, movement, (const Rectangle&) triangle))
return false;
-
+
Vector normal;
float c;
Vector p1;
- switch(triangle.dir) {
+ Vector tp1, tp2;
+ switch(triangle.dir & AATriangle::DEFORM_MASK) {
+ case 0:
+ tp1 = triangle.p1;
+ tp2 = triangle.p2;
+ break;
+ case AATriangle::DEFORM1:
+ tp1 = Vector(triangle.p1.x, triangle.p1.y + triangle.get_height()/2);
+ tp2 = triangle.p2;
+ break;
+ case AATriangle::DEFORM2:
+ tp1 = triangle.p1;
+ tp2 = Vector(triangle.p2.x, triangle.p1.y + triangle.get_height()/2);
+ break;
+ case AATriangle::DEFORM3:
+ tp1 = triangle.p1;
+ tp2 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p2.y);
+ break;
+ case AATriangle::DEFORM4:
+ tp1 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p1.y);
+ tp2 = triangle.p2;
+ break;
+ default:
+ assert(false);
+ }
+
+ switch(triangle.dir & AATriangle::DIRECTION_MASK) {
case AATriangle::SOUTHWEST:
p1 = Vector(rect.p1.x, rect.p2.y);
- makePlane(triangle.p1, triangle.p2, normal, c);
+ makePlane(tp1, tp2, normal, c);
break;
case AATriangle::NORTHEAST:
p1 = Vector(rect.p2.x, rect.p1.y);
- makePlane(triangle.p2, triangle.p1, normal, c);
+ makePlane(tp2, tp1, normal, c);
break;
case AATriangle::SOUTHEAST:
p1 = rect.p2;
- makePlane(Vector(triangle.p1.x, triangle.p2.y),
- Vector(triangle.p2.x, triangle.p1.y), normal, c);
+ makePlane(Vector(tp1.x, tp2.y),
+ Vector(tp2.x, tp1.y), normal, c);
break;
case AATriangle::NORTHWEST:
p1 = rect.p1;
- makePlane(Vector(triangle.p2.x, triangle.p1.y),
- Vector(triangle.p1.x, triangle.p2.y), normal, c);
+ makePlane(Vector(tp2.x, tp1.y),
+ Vector(tp1.x, tp2.y), normal, c);
break;
+ default:
+ assert(false);
}
- float depth = -(normal * p1) - c;
+ float n_p1 = -(normal * p1);
+ float depth = n_p1 - c;
if(depth < 0)
return false;
- if(depth < hit.depth) {
+ float time = depth / -(normal * movement);
+ if(time < hit.time) {
+ printf("Time: %f.\n", time);
hit.depth = depth;
+ hit.time = time;
hit.normal = normal;
}