src/supertux/collision.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include "supertux/collision.hpp"
00018 
00019 #include <algorithm>
00020 
00021 #include "math/aatriangle.hpp"
00022 #include "math/rectf.hpp"
00023 
00024 namespace collision {
00025 
00026 bool intersects(const Rectf& r1, const Rectf& r2)
00027 {
00028   if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
00029     return false;
00030   if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
00031     return false;
00032 
00033   return true;
00034 }
00035 
00036 //---------------------------------------------------------------------------
00037 
00038 namespace {
00039 inline void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c)
00040 {
00041   n = Vector(p2.y-p1.y, p1.x-p2.x);
00042   c = -(p2 * n);
00043   float nval = n.norm();
00044   n /= nval;
00045   c /= nval;
00046 }
00047 
00048 }
00049 
00050 bool rectangle_aatriangle(Constraints* constraints, const Rectf& rect,
00051                           const AATriangle& triangle, const Vector& addl_ground_movement)
00052 {
00053   if(!intersects(rect, (const Rectf&) triangle))
00054     return false;
00055 
00056   Vector normal;
00057   float c;
00058   Vector p1;
00059   Rectf area;
00060   switch(triangle.dir & AATriangle::DEFORM_MASK) {
00061     case 0:
00062       area.p1 = triangle.bbox.p1;
00063       area.p2 = triangle.bbox.p2;
00064       break;
00065     case AATriangle::DEFORM_BOTTOM:
00066       area.p1 = Vector(triangle.bbox.p1.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
00067       area.p2 = triangle.bbox.p2;
00068       break;
00069     case AATriangle::DEFORM_TOP:
00070       area.p1 = triangle.bbox.p1;
00071       area.p2 = Vector(triangle.bbox.p2.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
00072       break;
00073     case AATriangle::DEFORM_LEFT:
00074       area.p1 = triangle.bbox.p1;
00075       area.p2 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p2.y);
00076       break;
00077     case AATriangle::DEFORM_RIGHT:
00078       area.p1 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p1.y);
00079       area.p2 = triangle.bbox.p2;
00080       break;
00081     default:
00082       assert(false);
00083   }
00084 
00085   switch(triangle.dir & AATriangle::DIRECTION_MASK) {
00086     case AATriangle::SOUTHWEST:
00087       p1 = Vector(rect.p1.x, rect.p2.y);
00088       makePlane(area.p1, area.p2, normal, c);
00089       break;
00090     case AATriangle::NORTHEAST:
00091       p1 = Vector(rect.p2.x, rect.p1.y);
00092       makePlane(area.p2, area.p1, normal, c);
00093       break;
00094     case AATriangle::SOUTHEAST:
00095       p1 = rect.p2;
00096       makePlane(Vector(area.p1.x, area.p2.y),
00097                 Vector(area.p2.x, area.p1.y), normal, c);
00098       break;
00099     case AATriangle::NORTHWEST:
00100       p1 = rect.p1;
00101       makePlane(Vector(area.p2.x, area.p1.y),
00102                 Vector(area.p1.x, area.p2.y), normal, c);
00103       break;
00104     default:
00105       assert(false);
00106   }
00107 
00108   float n_p1 = -(normal * p1);
00109   float depth = n_p1 - c;
00110   if(depth < 0)
00111     return false;
00112 
00113 #if 0
00114   std::cout << "R: " << rect << " Tri: " << triangle << "\n";
00115   std::cout << "Norm: " << normal << " Depth: " << depth << "\n";
00116 #endif
00117 
00118   Vector outvec = normal * (depth + 0.2f);
00119 
00120   const float RDELTA = 3;
00121   if(p1.x < area.p1.x - RDELTA || p1.x > area.p2.x + RDELTA
00122      || p1.y < area.p1.y - RDELTA || p1.y > area.p2.y + RDELTA) {
00123     set_rectangle_rectangle_constraints(constraints, rect, area);
00124   } else {
00125     if(outvec.x < 0) {
00126       constraints->constrain_right(rect.get_right() + outvec.x, addl_ground_movement.x);
00127       constraints->hit.right = true;
00128     } else {
00129       constraints->constrain_left(rect.get_left() + outvec.x, addl_ground_movement.x);
00130       constraints->hit.left = true;
00131     }
00132 
00133     if(outvec.y < 0) {
00134       constraints->constrain_bottom(rect.get_bottom() + outvec.y, addl_ground_movement.y);
00135       constraints->hit.bottom = true;
00136       constraints->ground_movement += addl_ground_movement;
00137     } else {
00138       constraints->constrain_top(rect.get_top() + outvec.y, addl_ground_movement.y);
00139       constraints->hit.top = true;
00140     }
00141     constraints->hit.slope_normal = normal;
00142   }
00143 
00144   return true;
00145 }
00146 
00147 void set_rectangle_rectangle_constraints(Constraints* constraints,
00148                                          const Rectf& r1, const Rectf& r2, const Vector& addl_ground_movement)
00149 {
00150   float itop = r1.get_bottom() - r2.get_top();
00151   float ibottom = r2.get_bottom() - r1.get_top();
00152   float ileft = r1.get_right() - r2.get_left();
00153   float iright = r2.get_right() - r1.get_left();
00154 
00155   float vert_penetration = std::min(itop, ibottom);
00156   float horiz_penetration = std::min(ileft, iright);
00157   if(vert_penetration < horiz_penetration) {
00158     if(itop < ibottom) {
00159       constraints->constrain_bottom(r2.get_top(), addl_ground_movement.y);
00160       constraints->hit.bottom = true;
00161       constraints->ground_movement += addl_ground_movement;
00162     } else {
00163       constraints->constrain_top(r2.get_bottom(), addl_ground_movement.y);
00164       constraints->hit.top = true;
00165     }
00166   } else {
00167     if(ileft < iright) {
00168       constraints->constrain_right(r2.get_left(), addl_ground_movement.x);
00169       constraints->hit.right = true;
00170     } else {
00171       constraints->constrain_left(r2.get_right(), addl_ground_movement.x);
00172       constraints->hit.left = true;
00173     }
00174   }
00175 }
00176 
00177 }
00178 
00179 /* EOF */

Generated on Mon Jun 9 03:38:22 2014 for SuperTux by  doxygen 1.5.1