Index: Games/Pingus/src/actions/faller.cxx =================================================================== RCS file: /var/lib/cvs/Games/Pingus/src/actions/faller.cxx,v retrieving revision 1.39 diff -b -u -r1.39 faller.cxx --- Games/Pingus/src/actions/faller.cxx 25 Mar 2003 00:56:33 -0000 1.39 +++ Games/Pingus/src/actions/faller.cxx 15 Apr 2003 23:38:12 -0000 @@ -51,29 +51,33 @@ tumbler.update(); faller.update(); - // Pingu stands on ground - if (rel_getpixel(0, -1) != Groundtype::GP_NOTHING) - { - pingu->set_action(Actions::Walker); - return; - } - // FIXME: This should be triggered at a later point, when close to // FIXME: deadly_velocity or something like that. A translation // FIXME: animation for the floater might also help if (pingu->get_velocity().y > 5.0 && pingu->request_fall_action()) return; + float gravity = WorldObj::get_world()->get_gravity(); + Vector old_velocity = pingu->get_velocity(); + // Apply gravity - pingu->set_velocity(pingu->get_velocity() - + Vector(0.0f, WorldObj::get_world()->get_gravity()) ); + pingu->set_velocity(old_velocity + Vector (0.0f, gravity)); + Vector new_velocity = pingu->get_velocity(); - bool collided; + // Use equation [s = ut + 0.5at^2]. As t = 1 update in this case, + // [s = u + 0.5a]. Pingu used to use [s = u + a]. This resulted in a + // model where acceleration only occurred at integer update intervals + // (i.e. 1, 2, 3...). Acceleration in between the updates was not modelled. + // Using the proper equation enables acceleration in between the updates to + // be modelled. + Vector move = old_velocity + Vector(0.0f, 0.5f * gravity); + + Vector old_pos = pingu->get_pos(); - Vector velocity = pingu->get_velocity(); - Vector move = velocity; + Movers::LinearMover mover(WorldObj::get_world(), old_pos); - Movers::LinearMover mover(WorldObj::get_world(), pingu->get_pos()); + bool collided; + int pingu_action; do { @@ -89,47 +93,62 @@ { move = mover.remaining(); - // If the Pingu collided into something while moving down... - if (velocity.y > 0.0f - && rel_getpixel(0, -1) != Groundtype::GP_NOTHING) - { - // Ping is on ground/water/something - if ( rel_getpixel(0, -1) == Groundtype::GP_WATER - || rel_getpixel(0, -1) == Groundtype::GP_LAVA) + int collision_pixel = mover.collided_with(); + + if (collision_pixel == Groundtype::GP_WATER + || collision_pixel == Groundtype::GP_LAVA) { pingu->set_action(Actions::Drown); } - // Did we stop too fast? - else if (fabs(pingu->get_velocity().y) > deadly_velocity) + // If the Pingu collided into something while moving down... + else if (new_velocity.y > 0.0f + && rel_getpixel(0, -1) != Groundtype::GP_NOTHING) + { + float dist_to_ground = pingu->get_pos().y - old_pos.y; + + // Use equation [v^2 = u^2 + 2as] to work out at what velocity the + // Pingu hit the ground. + if (deadly_velocity * deadly_velocity <= + old_velocity.y * old_velocity.y + + 2.0f * gravity * dist_to_ground) { pingu->set_action(Actions::Splashed); } - else if (fabs(pingu->get_velocity().x) > deadly_velocity) + else { - pout(PINGUS_DEBUG_ACTIONS) << "Pingu: x Smashed on ground, jumping" << std::endl; - } + // Round down the Pingu's y pos otherwise a Pingu with y = 1.9 + // and another with y = 1.0 both on the same platform could + // react differently when falling off it. + pingu->set_pos(Vector(pingu->get_pos().x, + static_cast(pingu->get_pos().y)) ); + + // Pingu has safely collided with the ground + pingu->set_action(Actions::Walker); - break; + // Reset the velocity of the Pingu. + new_velocity.x = 0.0f; + new_velocity.y = 0.0f; + } } // If the Pingu collided into something while moving up... // NB: +1 because Mover backs out of something it has collided with. - else if (velocity.y < 0.0f + else if (new_velocity.y < 0.0f && rel_getpixel(0, pingu_height + 1) != Groundtype::GP_NOTHING) { // Don't make the Pingu go up any further. move.y = 0.0f; - velocity.y = 0.0f; + new_velocity.y = 0.0f; } else { // Make Pingu bounce off wall move.x = -(move.x / 3.0f); - velocity.x = -(velocity.x / 3.0f); + new_velocity.x = -(new_velocity.x / 3.0f); // Make the Pingu face the correct direction. NB: Pingu may // previously have been facing in the opposite direction of its // velocity because of an explosion. - if (velocity.x > 0.0f) + if (new_velocity.x > 0.0f) pingu->direction.right(); else pingu->direction.left(); @@ -137,10 +156,12 @@ } // Update the Pingu's velocity - pingu->set_velocity(velocity); + pingu->set_velocity(new_velocity); + + pingu_action = pingu->get_action(); } - // Loop if the Pingu still needs to be moved - while (collided); + // Loop if the Pingu still needs to be moved by the Faller code + while (collided && pingu_action == Actions::Faller); } void Index: Games/Pingus/src/actions/jumper.cxx =================================================================== RCS file: /var/lib/cvs/Games/Pingus/src/actions/jumper.cxx,v retrieving revision 1.19 diff -b -u -r1.19 jumper.cxx --- Games/Pingus/src/actions/jumper.cxx 25 Mar 2003 23:15:23 -0000 1.19 +++ Games/Pingus/src/actions/jumper.cxx 15 Apr 2003 23:38:13 -0000 @@ -17,10 +17,13 @@ // 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 "../vector.hxx" #include "../gui/graphic_context.hxx" #include "../pingu.hxx" #include "../string_converter.hxx" +#include "../world.hxx" +#include "../worldobj.hxx" #include "jumper.hxx" namespace Actions { @@ -41,10 +44,14 @@ void Jumper::update () { + // Using v^2 = u^2 + 2as gives us v = sqrt(2sa). In this case, sqrt(2s) is + // 10. + float velocity = 10.0f * sqrt(WorldObj::get_world()->get_gravity()); + if (pingu->direction.is_right()) { - pingu->set_velocity(pingu->get_velocity() + Vector(5.0, -5.0)); + pingu->set_velocity(pingu->get_velocity() + Vector(velocity, -velocity)); } else { - pingu->set_velocity(pingu->get_velocity() + Vector(-5.0, -5.0)); + pingu->set_velocity(pingu->get_velocity() + Vector(-velocity, -velocity)); } // Move the pingu in the air, so that it can start 'falling'