X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fcollision.cpp;h=8ae5e91bf13054dd9c2f3982c125ec4e1769c276;hb=d84d73b701cc7fa2bd74f3490b9be1bf8b6f705a;hp=cce522d5daa2d3dc22caa7540545fb15a52a4aff;hpb=1aa0de39a5f87bda1e74d0992848ad5142a850bc;p=supertux.git diff --git a/src/collision.cpp b/src/collision.cpp index cce522d5d..8ae5e91bf 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -1,7 +1,7 @@ // $Id$ -// +// // SuperTux -// Copyright (C) 2005 Matthias Braun +// Copyright (C) 2006 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -12,122 +12,84 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. #include -#include "collision.h" +#include "collision.hpp" #include #include #include #include #include -#include "math/vector.h" -#include "math/aatriangle.h" -#include "math/rect.h" -#include "collision_hit.h" +#include "math/vector.hpp" +#include "math/aatriangle.hpp" +#include "math/rect.hpp" +#include "collision_hit.hpp" +#include "log.hpp" -static const float DELTA = .0001; +namespace collision +{ -bool -Collision::rectangle_rectangle(CollisionHit& hit, const Rect& r1, - const Vector& movement, const Rect& r2) +bool intersects(const Rect& r1, const Rect& 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; - 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; - } - - 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; } //--------------------------------------------------------------------------- -static void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c) -{ - n = Vector(p2.y-p1.y, p1.x-p2.x); - c = -(p2 * n); - float nval = n.norm(); - n /= nval; - c /= nval; +namespace { + inline void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c) + { + n = Vector(p2.y-p1.y, p1.x-p2.x); + c = -(p2 * n); + float nval = n.norm(); + n /= nval; + c /= nval; + } + + static const float DELTA = .0001; } -bool -Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, - const Vector& movement, const AATriangle& triangle) +bool rectangle_aatriangle(Constraints* constraints, const Rect& rect, + const AATriangle& triangle) { - if(!rectangle_rectangle(hit, rect, movement, (const Rect&) triangle)) + if(!intersects(rect, (const Rect&) triangle)) return false; Vector normal; float c; Vector p1; - Vector tp1, tp2; + Rect area; switch(triangle.dir & AATriangle::DEFORM_MASK) { case 0: - tp1 = triangle.p1; - tp2 = triangle.p2; + area.p1 = triangle.p1; + area.p2 = triangle.p2; break; case AATriangle::DEFORM1: - tp1 = Vector(triangle.p1.x, triangle.p1.y + triangle.get_height()/2); - tp2 = triangle.p2; + area.p1 = Vector(triangle.p1.x, triangle.p1.y + triangle.get_height()/2); + area.p2 = triangle.p2; break; case AATriangle::DEFORM2: - tp1 = triangle.p1; - tp2 = Vector(triangle.p2.x, triangle.p1.y + triangle.get_height()/2); + area.p1 = triangle.p1; + area.p2 = 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); + area.p1 = triangle.p1; + area.p2 = 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; + area.p1 = Vector(triangle.p1.x + triangle.get_width()/2, triangle.p1.y); + area.p2 = triangle.p2; break; default: assert(false); @@ -136,21 +98,21 @@ Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, switch(triangle.dir & AATriangle::DIRECTION_MASK) { case AATriangle::SOUTHWEST: p1 = Vector(rect.p1.x, rect.p2.y); - makePlane(tp1, tp2, normal, c); + makePlane(area.p1, area.p2, normal, c); break; case AATriangle::NORTHEAST: p1 = Vector(rect.p2.x, rect.p1.y); - makePlane(tp2, tp1, normal, c); + makePlane(area.p2, area.p1, normal, c); break; case AATriangle::SOUTHEAST: p1 = rect.p2; - makePlane(Vector(tp1.x, tp2.y), - Vector(tp2.x, tp1.y), normal, c); + makePlane(Vector(area.p1.x, area.p2.y), + Vector(area.p2.x, area.p1.y), normal, c); break; case AATriangle::NORTHWEST: p1 = rect.p1; - makePlane(Vector(tp2.x, tp1.y), - Vector(tp1.x, tp2.y), normal, c); + makePlane(Vector(area.p2.x, area.p1.y), + Vector(area.p1.x, area.p2.y), normal, c); break; default: assert(false); @@ -160,13 +122,67 @@ Collision::rectangle_aatriangle(CollisionHit& hit, const Rect& rect, float depth = n_p1 - c; if(depth < 0) return false; - float time = depth / -(normal * movement); - if(time < hit.time) { - hit.depth = depth; - hit.time = time; - hit.normal = normal; - } +#if 0 + std::cout << "R: " << rect << " Tri: " << triangle << "\n"; + std::cout << "Norm: " << normal << " Depth: " << depth << "\n"; +#endif + + Vector outvec = normal * (depth + 0.2); + + const float RDELTA = 3; + if(p1.x < area.p1.x - RDELTA || p1.x > area.p2.x + RDELTA + || p1.y < area.p1.y - RDELTA || p1.y > area.p2.y + RDELTA) { + set_rectangle_rectangle_constraints(constraints, rect, area); + constraints->hit.left = false; + constraints->hit.right = false; + } else { + if(outvec.x < 0) { + constraints->right = rect.get_right() + outvec.x; + } else { + constraints->left = rect.get_left() + outvec.x; + } + + if(outvec.y < 0) { + constraints->bottom = rect.get_bottom() + outvec.y; + constraints->hit.bottom = true; + } else { + constraints->top = rect.get_top() + outvec.y; + constraints->hit.top = true; + } + constraints->hit.slope_normal = normal; + } + return true; } +void set_rectangle_rectangle_constraints(Constraints* constraints, + const Rect& r1, const Rect& r2) +{ + float itop = r1.get_bottom() - r2.get_top(); + float ibottom = r2.get_bottom() - r1.get_top(); + float ileft = r1.get_right() - r2.get_left(); + float iright = r2.get_right() - r1.get_left(); + + float vert_penetration = std::min(itop, ibottom); + float horiz_penetration = std::min(ileft, iright); + if(vert_penetration < horiz_penetration) { + if(itop < ibottom) { + constraints->bottom = std::min(constraints->bottom, r2.get_top()); + constraints->hit.bottom = true; + } else { + constraints->top = std::max(constraints->top, r2.get_bottom()); + constraints->hit.top = true; + } + } else { + if(ileft < iright) { + constraints->right = std::min(constraints->right, r2.get_left()); + constraints->hit.right = true; + } else { + constraints->left = std::max(constraints->left, r2.get_right()); + constraints->hit.left = true; + } + } +} + +}