From 54ebc2518ac4f4eb1fe1ee71c78fbe81a297c8ad Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Mon, 22 Feb 2010 10:21:22 +0000 Subject: [PATCH] supertux/{collision.[ch]pp,sector.cpp}: Store velocities in the constraints. 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 | 16 ++++----- src/supertux/collision.hpp | 85 +++++++++++++++++++++++++++++++++++----------- src/supertux/sector.cpp | 63 +++++++++++++++++----------------- 3 files changed, 105 insertions(+), 59 deletions(-) diff --git a/src/supertux/collision.cpp b/src/supertux/collision.cpp index c1a6e1822..b45065c08 100644 --- a/src/supertux/collision.cpp +++ b/src/supertux/collision.cpp @@ -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; } } diff --git a/src/supertux/collision.hpp b/src/supertux/collision.hpp index 01f3317c8..0e0787110 100644 --- a/src/supertux/collision.hpp +++ b/src/supertux/collision.hpp @@ -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::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::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::infinity() : std::numeric_limits::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 */ diff --git a/src/supertux/sector.cpp b/src/supertux/sector.cpp index 5a3aef4c2..2a5fe3db0 100644 --- a/src/supertux/sector.cpp +++ b/src/supertux/sector.cpp @@ -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 (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 */ -- 2.11.0