X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=lib%2Fspecial%2Fcollision.cpp;h=46ed0bf796152269a29f24133dc541d585e56831;hb=8e0bad9f82ccbc811a18edd7ce6c6f69c5bca082;hp=52197701271acfb43b186b39f48e2bed6e7f487d;hpb=d46c78c842ab4090a3f46e560c891234167f124b;p=supertux.git diff --git a/lib/special/collision.cpp b/lib/special/collision.cpp index 521977012..46ed0bf79 100644 --- a/lib/special/collision.cpp +++ b/lib/special/collision.cpp @@ -15,38 +15,56 @@ 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) { + hit.time = 0; + hit.depth = 0; + hit.normal.x = 1; + hit.normal.y = 0; + return true; + } + 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; @@ -65,40 +83,71 @@ static void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c) 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) { hit.depth = depth; + hit.time = time; hit.normal = normal; }