supertux/{collision.[ch]pp,sector.cpp}: Store velocities in the constraints.
authorFlorian Forster <supertux@octo.it>
Mon, 22 Feb 2010 10:21:22 +0000 (10:21 +0000)
committerFlorian Forster <supertux@octo.it>
Mon, 22 Feb 2010 10:21:22 +0000 (10:21 +0000)
Assume Tux is falling down with speed 2 and onto a downward moving tilemap with
speed 1. With the current constraints, his vertical motion will be set to zero,
possibly resulting in a hopping motion.

With normal, solid tiles this reset cannot be observed due to the way ground
movement is handled. With unisolid tiles, this results in said hopping.

This commit should be a non-functional change, i.e. the implementation differs
but the overall functionality should be unchanged.

SVN-Revision: 6389

src/supertux/collision.cpp
src/supertux/collision.hpp
src/supertux/sector.cpp

index c1a6e18..b45065c 100644 (file)
@@ -123,17 +123,17 @@ bool rectangle_aatriangle(Constraints* constraints, const Rectf& rect,
     set_rectangle_rectangle_constraints(constraints, rect, area);
   } else {
     if(outvec.x < 0) {
-      constraints->constrain_right(rect.get_right() + outvec.x);
+      constraints->constrain_right(rect.get_right() + outvec.x, addl_ground_movement.x);
     } else {
-      constraints->constrain_left(rect.get_left() + outvec.x);
+      constraints->constrain_left(rect.get_left() + outvec.x, addl_ground_movement.x);
     }
 
     if(outvec.y < 0) {
-      constraints->constrain_bottom(rect.get_bottom() + outvec.y);
+      constraints->constrain_bottom(rect.get_bottom() + outvec.y, addl_ground_movement.y);
       constraints->hit.bottom = true;
       constraints->ground_movement += addl_ground_movement;
     } else {
-      constraints->constrain_top(rect.get_top() + outvec.y);
+      constraints->constrain_top(rect.get_top() + outvec.y, addl_ground_movement.y);
       constraints->hit.top = true;
     }
     constraints->hit.slope_normal = normal;
@@ -154,19 +154,19 @@ void set_rectangle_rectangle_constraints(Constraints* constraints,
   float horiz_penetration = std::min(ileft, iright);
   if(vert_penetration < horiz_penetration) {
     if(itop < ibottom) {
-      constraints->constrain_bottom(r2.get_top());
+      constraints->constrain_bottom(r2.get_top(), addl_ground_movement.y);
       constraints->hit.bottom = true;
       constraints->ground_movement += addl_ground_movement;
     } else {
-      constraints->constrain_top(r2.get_bottom());
+      constraints->constrain_top(r2.get_bottom(), addl_ground_movement.y);
       constraints->hit.top = true;
     }
   } else {
     if(ileft < iright) {
-      constraints->constrain_right(r2.get_left());
+      constraints->constrain_right(r2.get_left(), addl_ground_movement.x);
       constraints->hit.right = true;
     } else {
-      constraints->constrain_left(r2.get_right());
+      constraints->constrain_left(r2.get_right(), addl_ground_movement.x);
       constraints->hit.left = true;
     }
   }
index 01f3317..0e07871 100644 (file)
@@ -31,20 +31,29 @@ class Constraints
 {
 public:
   Constraints() :
-    left(),
-    right(),
-    top(),
-    bottom(),
+    position_left(),
+    position_right(),
+    position_top(),
+    position_bottom(),
+    speed_left(),
+    speed_right(),
+    speed_top(),
+    speed_bottom(),
     ground_movement(),
     hit()
   {
     float infinity = (std::numeric_limits<float>::has_infinity ? 
                       std::numeric_limits<float>::infinity() : 
                       std::numeric_limits<float>::max());
-    left = -infinity;
-    right = infinity;
-    top = -infinity;
-    bottom = infinity;
+    position_left = -infinity;
+    position_right = infinity;
+    position_top = -infinity;
+    position_bottom = infinity;
+
+    speed_left = -infinity;
+    speed_right = infinity;
+    speed_top = -infinity;
+    speed_bottom = infinity;
   }
 
   bool has_constraints() const 
@@ -53,25 +62,61 @@ public:
                       std::numeric_limits<float>::infinity() : 
                       std::numeric_limits<float>::max());
     return
-      left   > -infinity || 
-      right  <  infinity || 
-      top    > -infinity || 
-      bottom <  infinity;
+      position_left   > -infinity || 
+      position_right  <  infinity || 
+      position_top    > -infinity || 
+      position_bottom <  infinity;
   }
 
 public:
-  float left;
-  float right;
-  float top;
-  float bottom;
 
-  void constrain_left  (float left2  ) { left   = std::max(left  , left2  ); }
-  void constrain_right (float right2 ) { right  = std::min(right , right2 ); }
-  void constrain_top   (float top2   ) { top    = std::max(top   , top2   ); }
-  void constrain_bottom(float bottom2) { bottom = std::min(bottom, bottom2); }
+  void constrain_left (float position, float velocity)
+  {
+    position_left = std::max (position_left, position);
+    speed_left = std::max (speed_left, velocity);
+  }
+
+  void constrain_right (float position, float velocity)
+  {
+    position_right = std::min (position_right, position);
+    speed_right = std::min (speed_right, velocity);
+  }
+
+  void constrain_top (float position, float velocity)
+  {
+    position_top = std::max (position_top, position);
+    speed_top = std::max (speed_top, velocity);
+  }
+
+  void constrain_bottom (float position, float velocity)
+  {
+    position_bottom = std::min (position_bottom, position);
+    speed_bottom = std::min (speed_bottom, velocity);
+  }
+
+  float get_position_left   (void) const { return position_left;   }
+  float get_position_right  (void) const { return position_right;  }
+  float get_position_top    (void) const { return position_top;    }
+  float get_position_bottom (void) const { return position_bottom; }
+
+  float get_height (void) const { return (position_bottom - position_top); }
+  float get_width  (void) const { return (position_right - position_left); }
+
+  float get_x_midpoint (void) const { return (.5f * (position_left + position_right)); }
 
   Vector ground_movement;
   CollisionHit hit;
+
+private:
+  float position_left;
+  float position_right;
+  float position_top;
+  float position_bottom;
+
+  float speed_left;
+  float speed_right;
+  float speed_top;
+  float speed_bottom;
 };
 
 /** checks if 2 rectangle intersect each other */
index 5a3aef4..2a5fe3d 100644 (file)
@@ -882,10 +882,10 @@ Sector::draw(DrawingContext& context)
 
 /** r1 is supposed to be moving, r2 a solid object */
 void check_collisions(collision::Constraints* constraints,
-                      const Vector& movement, const Rectf& r1, const Rectf& r2,
-                      GameObject* object = NULL, MovingObject* other = NULL, const Vector& addl_ground_movement = Vector(0,0))
+                      const Vector& obj_movement, const Rectf& obj_rect, const Rectf& other_rect,
+                      GameObject* object = NULL, MovingObject* other = NULL, const Vector& other_movement = Vector(0,0))
 {
-  if(!collision::intersects(r1, r2))
+  if(!collision::intersects(obj_rect, other_rect))
     return;
 
   MovingObject *moving_object = dynamic_cast<MovingObject*> (object);
@@ -896,31 +896,31 @@ void check_collisions(collision::Constraints* constraints,
     return;
 
   // calculate intersection
-  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 itop    = obj_rect.get_bottom() - other_rect.get_top();
+  float ibottom = other_rect.get_bottom() - obj_rect.get_top();
+  float ileft   = obj_rect.get_right() - other_rect.get_left();
+  float iright  = other_rect.get_right() - obj_rect.get_left();
 
-  if(fabsf(movement.y) > fabsf(movement.x)) {
+  if(fabsf(obj_movement.y) > fabsf(obj_movement.x)) {
     if(ileft < SHIFT_DELTA) {
-      constraints->constrain_right(r2.get_left());
+      constraints->constrain_right(other_rect.get_left(), other_movement.x);
       return;
     } else if(iright < SHIFT_DELTA) {
-      constraints->constrain_left(r2.get_right());
+      constraints->constrain_left(other_rect.get_right(), other_movement.x);
       return;
     }
   } else {
     // shiftout bottom/top
     if(itop < SHIFT_DELTA) {
-      constraints->constrain_bottom(r2.get_top());
+      constraints->constrain_bottom(other_rect.get_top(), other_movement.y);
       return;
     } else if(ibottom < SHIFT_DELTA) {
-      constraints->constrain_top(r2.get_bottom());
+      constraints->constrain_top(other_rect.get_bottom(), other_movement.y);
       return;
     }
   }
 
-  constraints->ground_movement += addl_ground_movement;
+  constraints->ground_movement += other_movement;
   if(other != NULL) {
     HitResponse response = other->collision(*object, dummy);
     if(response == ABORT_MOVE)
@@ -936,18 +936,18 @@ void check_collisions(collision::Constraints* constraints,
   float horiz_penetration = std::min(ileft, iright);
   if(vert_penetration < horiz_penetration) {
     if(itop < ibottom) {
-      constraints->constrain_bottom(r2.get_top());
+      constraints->constrain_bottom(other_rect.get_top(), other_movement.y);
       constraints->hit.bottom = true;
     } else {
-      constraints->constrain_top(r2.get_bottom());
+      constraints->constrain_top(other_rect.get_bottom(), other_movement.y);
       constraints->hit.top = true;
     }
   } else {
     if(ileft < iright) {
-      constraints->constrain_right(r2.get_left());
+      constraints->constrain_right(other_rect.get_left(), other_movement.x);
       constraints->hit.right = true;
     } else {
-      constraints->constrain_left(r2.get_right());
+      constraints->constrain_left(other_rect.get_right(), other_movement.x);
       constraints->hit.left = true;
     }
   }
@@ -1459,17 +1459,17 @@ Sector::collision_static_constrains(MovingObject& object)
       break;
 
     // apply calculated horizontal constraints
-    if(constraints.bottom < infinity) {
-      float height = constraints.bottom - constraints.top;
+    if(constraints.get_position_bottom() < infinity) {
+      float height = constraints.get_height ();
       if(height < oheight) {
         // we're crushed, but ignore this for now, we'll get this again
         // later if we're really crushed or things will solve itself when
         // looking at the vertical constraints
       }
-      dest.p2.y = constraints.bottom - DELTA;
+      dest.p2.y = constraints.get_position_bottom() - DELTA;
       dest.p1.y = dest.p2.y - oheight;
-    } else if(constraints.top > -infinity) {
-      dest.p1.y = constraints.top + DELTA;
+    } else if(constraints.get_position_top() > -infinity) {
+      dest.p1.y = constraints.get_position_top() + DELTA;
       dest.p2.y = dest.p1.y + oheight;
     }
   }
@@ -1491,12 +1491,12 @@ Sector::collision_static_constrains(MovingObject& object)
       break;
 
     // apply calculated vertical constraints
-    float width = constraints.right - constraints.left;
+    float width = constraints.get_width ();
     if(width < infinity) {
       if(width + SHIFT_DELTA < owidth) {
 #if 0
         printf("Object %p crushed horizontally... L:%f R:%f\n", &object,
-               constraints.left, constraints.right);
+               constraints.get_position_left(), constraints.get_position_right());
 #endif
         CollisionHit h;
         h.left = true;
@@ -1504,15 +1504,15 @@ Sector::collision_static_constrains(MovingObject& object)
         h.crush = true;
         object.collision_solid(h);
       } else {
-        float xmid = (constraints.left + constraints.right) / 2;
+        float xmid = constraints.get_x_midpoint ();
         dest.p1.x = xmid - owidth/2;
         dest.p2.x = xmid + owidth/2;
       }
-    } else if(constraints.right < infinity) {
-      dest.p2.x = constraints.right - DELTA;
+    } else if(constraints.get_position_right() < infinity) {
+      dest.p2.x = constraints.get_position_right() - DELTA;
       dest.p1.x = dest.p2.x - owidth;
-    } else if(constraints.left > -infinity) {
-      dest.p1.x = constraints.left + DELTA;
+    } else if(constraints.get_position_left() > -infinity) {
+      dest.p1.x = constraints.get_position_left() + DELTA;
       dest.p2.x = dest.p1.x + owidth;
     }
   }
@@ -1527,8 +1527,8 @@ Sector::collision_static_constrains(MovingObject& object)
   // an extra pass to make sure we're not crushed horizontally
   constraints = Constraints();
   collision_static(&constraints, movement, dest, object);
-  if(constraints.bottom < infinity) {
-    float height = constraints.bottom - constraints.top;
+  if(constraints.get_position_bottom() < infinity) {
+    float height = constraints.get_height ();
     if(height + SHIFT_DELTA < oheight) {
 #if 0
       printf("Object %p crushed vertically...\n", &object);
@@ -1893,4 +1893,5 @@ Sector::get_gravity() const
   return gravity;
 }
 
+/* vim: set sw=2 sts=2 et : */
 /* EOF */