Index: ./Games/Pingus/src/actions/bomber.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/actions/bomber.cxx,v
retrieving revision 1.32
diff -u -r1.32 bomber.cxx
--- ./Games/Pingus/src/actions/bomber.cxx 18 Mar 2003 17:03:02 -0000 1.32
+++ ./Games/Pingus/src/actions/bomber.cxx 5 Apr 2003 23:43:14 -0000
@@ -82,7 +82,9 @@
{
sprite.update ();
- Movers::LinearMover mover(WorldObj::get_world(), pingu->get_pos());
+ Vector old_pos = pingu->get_pos();
+
+ Movers::LinearMover mover(WorldObj::get_world(), old_pos);
Vector velocity = pingu->get_velocity();
@@ -99,9 +101,15 @@
return;
}
- // If the Bomber hasn't 'exploded' yet and it has hit the ground too quickly
+ float dist_to_ground = pingu->get_pos().y - old_pos.y;
+ float gravity = WorldObj::get_world()->get_gravity();
+
+ // If the Bomber hasn't 'exploded' yet and it has hit the ground too quickly.
+ // Use equation [v^2 = u^2 + 2as] to work out at what velocity the Pingu hit
+ // the ground.
if (sprite.get_frame () <= 9 && rel_getpixel(0, -1) != Groundtype::GP_NOTHING
- && velocity.y > deadly_velocity)
+ && deadly_velocity * deadly_velocity <= velocity.y * velocity.y
+ + 2.0f * gravity * dist_to_ground)
{
pingu->set_action(Actions::Splashed);
return;
Index: ./Games/Pingus/src/actions/faller.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/actions/faller.cxx,v
retrieving revision 1.34
diff -u -r1.34 faller.cxx
--- ./Games/Pingus/src/actions/faller.cxx 3 Nov 2002 22:20:29 -0000 1.34
+++ ./Games/Pingus/src/actions/faller.cxx 5 Apr 2003 23:43:15 -0000
@@ -1,4 +1,4 @@
-// $Id: faller.cxx,v 1.34 2002/11/03 22:20:29 grumbel Exp $
+// $Id: faller.cxx,v 1.39 2003/03/25 00:56:33 grumbel Exp $
//
// Pingus - A free Lemmings clone
// Copyright (C) 2000 Ingo Ruhnke
@@ -19,17 +19,19 @@
#include
#include "../col_map.hxx"
+#include "../colliders/pingu_collider.hxx"
#include "../debug.hxx"
#include "../globals.hxx"
-#include "../graphic_context.hxx"
+#include "../gui/graphic_context.hxx"
+#include "../movers/linear_mover.hxx"
#include "../pingu.hxx"
#include "../string_converter.hxx"
+#include "../world.hxx"
+#include "../worldobj.hxx"
#include "faller.hxx"
namespace Actions {
-const float Faller::deadly_velocity = 20.0f;
-
Faller::Faller (Pingu* p)
: PinguAction(p),
faller(Sprite("Pingus/faller" + to_string(pingu->get_owner ()), "pingus")),
@@ -49,47 +51,117 @@
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;
- // Move the Faller according to the forces that currently exist, which
- // includes gravity.
- move_with_forces ();
-
- // Now that the Pingu is moved, check if he hits the ground.
- // FIXME: shouldn't this be done by move_with_forces
- if (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)
- {
- pingu->set_action(Actions::Drown);
- return;
- }
- else
+ float gravity = WorldObj::get_world()->get_gravity();
+ Vector old_velocity = pingu->get_velocity();
+
+ // Apply gravity
+ pingu->set_velocity(old_velocity + Vector (0.0f, gravity));
+ Vector new_velocity = pingu->get_velocity();
+
+ // 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 only 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();
+
+ Movers::LinearMover mover(WorldObj::get_world(), old_pos);
+
+ bool collided;
+ int pingu_action;
+
+ do
+ {
+ // Move the Pingu as far is it can go
+ mover.update(move, Colliders::PinguCollider(pingu_height));
+
+ pingu->set_pos(mover.get_pos());
+
+ collided = mover.collided();
+
+ // If the Pingu collided with something...
+ if (collided)
{
- // Did we stop too fast?
- if (fabs(pingu->get_velocity().y) > deadly_velocity)
+ move = mover.remaining();
+
+ int collision_pixel = mover.collided_with();
+
+ if (collision_pixel == Groundtype::GP_WATER
+ || collision_pixel == Groundtype::GP_LAVA)
{
- pingu->set_action(Actions::Splashed);
- return;
+ pingu->set_action(Actions::Drown);
}
- else if (fabs(pingu->get_velocity().x) > 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)
{
- pout(PINGUS_DEBUG_ACTIONS) << "Pingu: x Smashed on ground, jumping" << std::endl;
+ 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
+ {
+ // 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);
+
+ // 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 (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;
+ new_velocity.y = 0.0f;
+ }
+ else
+ {
+ // Make Pingu bounce off wall
+ move.x = -(move.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 (new_velocity.x > 0.0f)
+ pingu->direction.right();
+ else
+ pingu->direction.left();
}
}
+
+ // Update the Pingu's velocity
+ pingu->set_velocity(new_velocity);
+
+ pingu_action = pingu->get_action();
}
+ // 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.18
diff -u -r1.18 jumper.cxx
--- ./Games/Pingus/src/actions/jumper.cxx 19 Feb 2003 09:50:36 -0000 1.18
+++ ./Games/Pingus/src/actions/jumper.cxx 5 Apr 2003 23:43:15 -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(10.0, -10.0));
+ pingu->set_velocity(pingu->get_velocity() + Vector(velocity, -velocity));
} else {
- pingu->set_velocity(pingu->get_velocity() + Vector(-10.0, -10.0));
+ pingu->set_velocity(pingu->get_velocity() + Vector(-velocity, -velocity));
}
// Move the pingu in the air, so that it can start 'falling'
Index: ./Games/Pingus/src/actions/walker.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/actions/walker.cxx,v
retrieving revision 1.32
diff -u -r1.32 walker.cxx
--- ./Games/Pingus/src/actions/walker.cxx 4 Mar 2003 11:26:18 -0000 1.32
+++ ./Games/Pingus/src/actions/walker.cxx 5 Apr 2003 23:43:16 -0000
@@ -64,7 +64,12 @@
*/
- if (rel_getpixel(0, -1) == Groundtype::GP_WATER)
+ if (rel_getpixel(0, -1) == Groundtype::GP_WATER
+ || rel_getpixel(0, -1) == Groundtype::GP_LAVA
+ || rel_getpixel(1, 0) == Groundtype::GP_WATER
+ || rel_getpixel(1, 0) == Groundtype::GP_LAVA
+ || rel_getpixel(1, pingu_height) == Groundtype::GP_WATER
+ || rel_getpixel(1, pingu_height) == Groundtype::GP_LAVA)
{
pingu->set_action(Actions::Drown);
return;
Index: ./Games/Pingus/src/mover.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/mover.cxx,v
retrieving revision 1.2
diff -u -r1.2 mover.cxx
--- ./Games/Pingus/src/mover.cxx 9 Mar 2003 20:41:30 -0000 1.2
+++ ./Games/Pingus/src/mover.cxx 5 Apr 2003 23:43:17 -0000
@@ -31,6 +31,13 @@
{
}
+void Mover::operator() (const bool& collided_arg,
+ const int& collision_pixel_arg)
+{
+ collision = collided_arg;
+ collision_pixel = collision_pixel_arg;
+}
+
Vector Mover::get_pos() const
{
return pos;
@@ -44,6 +51,11 @@
bool Mover::collided() const
{
return collision;
+}
+
+int Mover::collided_with() const
+{
+ return collision_pixel;
}
/* EOF */
Index: ./Games/Pingus/src/mover.hxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/mover.hxx,v
retrieving revision 1.2
diff -u -r1.2 mover.hxx
--- ./Games/Pingus/src/mover.hxx 9 Mar 2003 20:41:30 -0000 1.2
+++ ./Games/Pingus/src/mover.hxx 5 Apr 2003 23:43:17 -0000
@@ -34,6 +34,10 @@
/** Destructor of abstract class */
virtual ~Mover() = 0;
+ /** Sets the status variables of the mover. Crucially used by Colliders. */
+ void operator() (const bool& collided_arg,
+ const int& collision_pixel_arg);
+
/** Updates the position of the object taking into account collisions */
virtual void update(const Vector& move, const Collider& collider) = 0;
@@ -46,6 +50,9 @@
/** Get whether object stopped moving because it collided with something */
bool collided() const;
+ /** Get the "pixel" that the object collided with */
+ int collided_with() const;
+
protected:
/** World in which the object should move */
World* const world;
@@ -56,8 +63,12 @@
/** Move vector remaining after a collision */
Vector remaining_move;
+ private:
/** Flag to denote whether object has had a collision */
bool collision;
+
+ /** The "pixel" that the object collided with */
+ int collision_pixel;
};
#endif
Index: ./Games/Pingus/src/pingu_enums.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/pingu_enums.cxx,v
retrieving revision 1.4
diff -u -r1.4 pingu_enums.cxx
--- ./Games/Pingus/src/pingu_enums.cxx 25 Mar 2003 00:56:33 -0000 1.4
+++ ./Games/Pingus/src/pingu_enums.cxx 5 Apr 2003 23:43:17 -0000
@@ -19,9 +19,10 @@
#include "pingu_enums.hxx"
-// Pingu "globals". Make [deadly_velocity = 20 * sqrt("normal gravity")] so
-// that the "deadly distance" is the same and therefore doesn't break levels.
-const float deadly_velocity = 10.0f;
+// Pingu "globals". Make deadly_velocity above sqrt(2 * 210 pixels * "normal
+// gravity") and below sqrt(2 * 211 pixels * "normal gravity") so that the
+// "deadly distance" is the same and therefore doesn't break levels.
+const float deadly_velocity = 10.26f;
const int pingu_height = 26;
namespace Actions {
Index: ./Games/Pingus/src/collider.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/collider.cxx,v
retrieving revision 1.3
diff -u -r1.3 collider.cxx
--- ./Games/Pingus/src/collider.cxx 18 Mar 2003 17:03:01 -0000 1.3
+++ ./Games/Pingus/src/collider.cxx 5 Apr 2003 23:43:18 -0000
@@ -30,14 +30,13 @@
{
}
-bool Collider::operator() (World* const world, Vector current_pos,
+void Collider::operator() (Mover& mover, World* const world,
+ const Vector& current_pos,
const Vector& step_vector) const
{
UNUSED_ARG(world);
UNUSED_ARG(current_pos);
UNUSED_ARG(step_vector);
-
- return false;
}
int Collider::getpixel(World* const world, const Vector& pos) const
Index: ./Games/Pingus/src/collider.hxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/collider.hxx,v
retrieving revision 1.3
diff -u -r1.3 collider.hxx
--- ./Games/Pingus/src/collider.hxx 18 Mar 2003 17:03:01 -0000 1.3
+++ ./Games/Pingus/src/collider.hxx 5 Apr 2003 23:43:18 -0000
@@ -20,6 +20,7 @@
#ifndef HEADER_PINGUS_COLLIDER_HXX
#define HEADER_PINGUS_COLLIDER_HXX
+class Mover;
class Vector;
class World;
@@ -33,8 +34,10 @@
virtual ~Collider() = 0;
/** Find out if object will collide with something */
- virtual bool operator() (World* const world, Vector current_pos,
- const Vector& step_vector) const = 0;
+ virtual void operator() (Mover& mover, World* const world,
+ const Vector& current_pos,
+ const Vector& step_vector)
+ const = 0;
protected:
/** Get the Collision Map pixel at the specified position in the specified
Index: ./Games/Pingus/src/colliders/pingu_collider.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/colliders/pingu_collider.cxx,v
retrieving revision 1.3
diff -u -r1.3 pingu_collider.cxx
--- ./Games/Pingus/src/colliders/pingu_collider.cxx 18 Mar 2003 17:03:02 -0000 1.3
+++ ./Games/Pingus/src/colliders/pingu_collider.cxx 5 Apr 2003 23:43:19 -0000
@@ -17,6 +17,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include "../mover.hxx"
#include "../pingu_action.hxx"
#include "../groundtype.hxx"
#include "../vector.hxx"
@@ -32,55 +33,57 @@
{
}
-bool PinguCollider::operator() (World* const world, Vector current_pos,
+void PinguCollider::operator() (Mover& mover, World* const world,
+ const Vector& current_pos,
const Vector& step_vector) const
{
- Vector new_pos = current_pos + step_vector;
- int pixel;
bool falling = false;
- bool collided = false;
if (step_vector.y > 0.0f)
falling = true;
- // If the Pingu is going to move sideways to the next pixel...
- if (static_cast(new_pos.x) != static_cast(current_pos.x))
+ Vector check_pos = current_pos + step_vector;
+ float final_check_pos_y = check_pos.y - height;
+
+ // If the Pingu is not moving sideways when going to the next pixel...
+ if (static_cast(check_pos.x) == static_cast(current_pos.x))
{
- float top_of_pingu = new_pos.y - height;
+ // ...make loop only check the top or bottom pixel of the Pingu
+ if (falling)
+ final_check_pos_y = check_pos.y;
+ else
+ check_pos.y = final_check_pos_y;
+ }
- for (; new_pos.y >= top_of_pingu; --new_pos.y)
- {
- pixel = getpixel(world, new_pos);
+ int colmap_pixel;
+ int collision_pixel;
+ bool collided = false;
- // If there is something in the way, then Pingu has collided with
- // something. However, if not falling and colliding with a
- // Bridge, allow Pingu to go through it.
- if ((!falling || pixel != Groundtype::GP_BRIDGE)
- && pixel != Groundtype::GP_NOTHING)
- {
- collided = true;
- break;
- }
- }
- }
- // If the Pingu is not falling...
- else if (!falling)
+ for (; check_pos.y >= final_check_pos_y; --check_pos.y)
{
- pixel = getpixel(world, Vector(new_pos.x, new_pos.y - height));
+ colmap_pixel = getpixel(world, check_pos);
- // If the top of the Pingu has hit something except a bridge...
- if (pixel != Groundtype::GP_NOTHING && pixel != Groundtype::GP_BRIDGE)
+ // If there is something in the way, then Pingu has collided with
+ // something. However, if not falling and colliding with a
+ // Bridge, allow Pingu to go through it.
+ if ((!falling || colmap_pixel != Groundtype::GP_BRIDGE)
+ && colmap_pixel != Groundtype::GP_NOTHING)
{
collided = true;
+ collision_pixel = colmap_pixel;
+
+ // If a deadly pixel is found...
+ if (colmap_pixel == Groundtype::GP_WATER
+ || colmap_pixel == Groundtype::GP_LAVA)
+ {
+ // ...get out of the loop.
+ break;
+ }
}
}
- // If the Pingu's "feet" has hit something...
- else if (getpixel(world, new_pos) != Groundtype::GP_NOTHING)
- {
- collided = true;
- }
- return collided;
+ // Pass back information to the mover.
+ mover(collided, collision_pixel);
}
} // namespace Colliders
Index: ./Games/Pingus/src/colliders/pingu_collider.hxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/colliders/pingu_collider.hxx,v
retrieving revision 1.3
diff -u -r1.3 pingu_collider.hxx
--- ./Games/Pingus/src/colliders/pingu_collider.hxx 18 Mar 2003 17:03:02 -0000 1.3
+++ ./Games/Pingus/src/colliders/pingu_collider.hxx 5 Apr 2003 23:43:19 -0000
@@ -35,8 +35,9 @@
/** Find out if a Pingu at the specified position is colliding with
something */
- bool operator() (World* const world, Vector current_pos,
- const Vector& step_vector) const;
+ void operator() (Mover& mover, World* const world,
+ const Vector& current_pos, const Vector& step_vector)
+ const;
private:
/** Pingu could be on its belly. Therefore, this is the current height of
Index: ./Games/Pingus/src/movers/linear_mover.cxx
===================================================================
RCS file: /var/lib/cvs/Games/Pingus/src/movers/linear_mover.cxx,v
retrieving revision 1.3
diff -u -r1.3 linear_mover.cxx
--- ./Games/Pingus/src/movers/linear_mover.cxx 18 Mar 2003 17:03:02 -0000 1.3
+++ ./Games/Pingus/src/movers/linear_mover.cxx 5 Apr 2003 23:43:19 -0000
@@ -19,6 +19,7 @@
#include "linear_mover.hxx"
#include "../collider.hxx"
+#include "../groundtype.hxx"
namespace Movers {
@@ -42,18 +43,23 @@
// Make the step vector (i.e. change to a unit vector)
step_vector.normalize();
- collision = false;
+ // Reset the status of the mover.
+ (*this)(false, Groundtype::GP_NOTHING);
// Move to the destination one unit vector at a time
- for (int i = 0; i < move_length && !collision; ++i)
+ for (int i = 0; i <= move_length && !collided(); ++i)
{
- collision = collision_check(world, pos, step_vector);
+ // If a fraction of a move is left...
+ if (i == move_length)
+ step_vector = target_pos - pos;
+
+ collision_check(*this, world, pos, step_vector);
pos += step_vector;
}
// If on a collision pixel, back away from it.
- if (collision)
+ if (collided())
pos -= step_vector;
remaining_move = target_pos - pos;