Added support for physical objects triggering rescue on collision

(#163). Objects must be declared with 'reset="Y"' in order
to trigger rescue.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@9910 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2011-09-28 10:52:41 +00:00
parent 3e32b840bf
commit 2b805c7d69
3 changed files with 107 additions and 48 deletions

View File

@ -45,11 +45,13 @@ PhysicalObject::PhysicalObject(const XMLNode &xml_node)
m_motion_state = NULL; m_motion_state = NULL;
m_mass = 1; m_mass = 1;
m_radius = -1; m_radius = -1;
m_crash_reset = false;
std::string shape; std::string shape;
xml_node.get("mass", &m_mass ); xml_node.get("mass", &m_mass );
xml_node.get("radius", &m_radius ); xml_node.get("radius", &m_radius );
xml_node.get("shape", &shape ); xml_node.get("shape", &shape );
xml_node.get("reset", &m_crash_reset);
m_body_type = MP_NONE; m_body_type = MP_NONE;
if (shape=="cone" || if (shape=="cone" ||

View File

@ -42,20 +42,26 @@ public:
MP_CYLINDER_Y, MP_CYLINDER_X, MP_CYLINDER_Z, MP_CYLINDER_Y, MP_CYLINDER_X, MP_CYLINDER_Z,
MP_BOX, MP_SPHERE}; MP_BOX, MP_SPHERE};
protected: private:
/** The shape of this object. */ /** The shape of this object. */
bodyTypes m_body_type; bodyTypes m_body_type;
/** The bullet collision shape. */ /** The bullet collision shape. */
btCollisionShape *m_shape; btCollisionShape *m_shape;
/** The corresponding bullet rigid body. */ /** The corresponding bullet rigid body. */
btRigidBody *m_body; btRigidBody *m_body;
/** Bullet's motion state for this object. */ /** Bullet's motion state for this object. */
btDefaultMotionState *m_motion_state; btDefaultMotionState *m_motion_state;
/** The mass of this object. */ /** The mass of this object. */
float m_mass; float m_mass;
/** The pointer that is stored in the bullet rigid body back to /** The pointer that is stored in the bullet rigid body back to
* this object. */ * this object. */
UserPointer m_user_pointer; UserPointer m_user_pointer;
/** This is the initial position of the object for the physics. */ /** This is the initial position of the object for the physics. */
btTransform m_init_pos; btTransform m_init_pos;
@ -66,6 +72,10 @@ protected:
* details, but is supposed to be a sphere). In this case the radius * details, but is supposed to be a sphere). In this case the radius
* can be set in the scene file. */ * can be set in the scene file. */
float m_radius; float m_radius;
/** True if a kart colliding with this object should be rescued. */
bool m_crash_reset;
public: public:
PhysicalObject (const XMLNode &node); PhysicalObject (const XMLNode &node);
@ -76,12 +86,17 @@ public:
const core::vector3df& scale); const core::vector3df& scale);
virtual ~PhysicalObject (); virtual ~PhysicalObject ();
virtual void reset ();
virtual void handleExplosion(const Vec3& pos, bool directHit);
void update (float dt); void update (float dt);
void init (); void init ();
virtual void reset (); // ------------------------------------------------------------------------
/** Returns the rigid body of this physical object. */ /** Returns the rigid body of this physical object. */
btRigidBody *getBody () { return m_body; } btRigidBody *getBody () { return m_body; }
virtual void handleExplosion(const Vec3& pos, bool directHit); // ------------------------------------------------------------------------
/** Returns true if this object should trigger a rescue in a kart that
* hits it. */
bool isCrashReset() const { return m_crash_reset; }
}; // PhysicalObject }; // PhysicalObject
#endif #endif

View File

@ -25,6 +25,7 @@
#include "physics/btKart.hpp" #include "physics/btKart.hpp"
#include "physics/btUprightConstraint.hpp" #include "physics/btUprightConstraint.hpp"
#include "physics/irr_debug_drawer.hpp" #include "physics/irr_debug_drawer.hpp"
#include "physics/physical_object.hpp"
#include "physics/triangle_mesh.hpp" #include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
@ -99,7 +100,7 @@ void Physics::removeKart(const Kart *kart)
void Physics::update(float dt) void Physics::update(float dt)
{ {
// Bullet can report the same collision more than once (up to 4 // Bullet can report the same collision more than once (up to 4
// contact points per collision. Additionally, more than one internal // contact points per collision). Additionally, more than one internal
// substep might be taken, resulting in potentially even more // substep might be taken, resulting in potentially even more
// duplicates. To handle this, all collisions (i.e. pair of objects) // duplicates. To handle this, all collisions (i.e. pair of objects)
// are stored in a vector, but only one entry per collision pair // are stored in a vector, but only one entry per collision pair
@ -110,33 +111,59 @@ void Physics::update(float dt)
// 20 FPS (bullet default frequency is 60 HZ). // 20 FPS (bullet default frequency is 60 HZ).
m_dynamics_world->stepSimulation(dt, 3); m_dynamics_world->stepSimulation(dt, 3);
// Now handle the actual collision. Note: rockets can not be removed // Now handle the actual collision. Note: flyables can not be removed
// inside of this loop, since the same rocket might hit more than one // inside of this loop, since the same flyables might hit more than one
// other object. So, only a flag is set in the rockets, the actual // other object. So only a flag is set in the flyables, the actual
// clean up is then done later in the projectile manager. // clean up is then done later in the projectile manager.
std::vector<CollisionPair>::iterator p; std::vector<CollisionPair>::iterator p;
for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p) for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p)
{ {
if(p->a->is(UserPointer::UP_KART)) { // kart-kart collision // Kart-kart collision
// --------------------
if(p->a->is(UserPointer::UP_KART))
{
Kart *a=p->a->getPointerKart(); Kart *a=p->a->getPointerKart();
Kart *b=p->b->getPointerKart(); Kart *b=p->b->getPointerKart();
race_state->addCollision(a->getWorldKartId(), race_state->addCollision(a->getWorldKartId(),
b->getWorldKartId()); b->getWorldKartId());
KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart()); KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart());
continue;
} // if kart-kart collision } // if kart-kart collision
else // now the first object must be a projectile
if(p->a->is(UserPointer::UP_PHYSICAL_OBJECT))
{ {
if(p->b->is(UserPointer::UP_TRACK)) // must be projectile hit track // Kart hits physical object
// -------------------------
PhysicalObject *obj = p->a->getPointerPhysicalObject();
if(obj->isCrashReset())
{ {
Kart *kart = p->b->getPointerKart();
kart->forceRescue();
}
continue;
}
// now the first object must be a projectile
// =========================================
if(p->b->is(UserPointer::UP_TRACK))
{
// Projectile hits track
// ---------------------
p->a->getPointerFlyable()->hitTrack(); p->a->getPointerFlyable()->hitTrack();
} }
else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT)) else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT))
{ {
p->a->getPointerFlyable()->hit(NULL, p->b->getPointerPhysicalObject()); // Projectile hits physical object
// -------------------------------
p->a->getPointerFlyable()
->hit(NULL, p->b->getPointerPhysicalObject());
} }
else if(p->b->is(UserPointer::UP_KART)) // projectile hit kart else if(p->b->is(UserPointer::UP_KART))
{ {
// Projectile hits kart
// --------------------
// Only explode a bowling ball if the target is // Only explode a bowling ball if the target is
// not invulnerable // not invulnerable
if(p->a->getPointerFlyable()->getType() if(p->a->getPointerFlyable()->getType()
@ -144,12 +171,13 @@ void Physics::update(float dt)
!p->b->getPointerKart()->isInvulnerable() ) !p->b->getPointerKart()->isInvulnerable() )
p->a->getPointerFlyable()->hit(p->b->getPointerKart()); p->a->getPointerFlyable()->hit(p->b->getPointerKart());
} }
else // projectile hits projectile else
{ {
// Projectile hits projectile
// --------------------------
p->a->getPointerFlyable()->hit(NULL); p->a->getPointerFlyable()->hit(NULL);
p->b->getPointerFlyable()->hit(NULL); p->b->getPointerFlyable()->hit(NULL);
} }
}
} // for all p in m_all_collisions } // for all p in m_all_collisions
} // update } // update
@ -161,15 +189,16 @@ void Physics::update(float dt)
bool Physics::projectKartDownwards(const Kart *k) bool Physics::projectKartDownwards(const Kart *k)
{ {
btVector3 hell(0, -10000, 0); btVector3 hell(0, -10000, 0);
return k->getVehicle()->projectVehicleToSurface(hell, true /*allow translation*/); return k->getVehicle()->projectVehicleToSurface(hell,
/*allow translation*/true);
} //projectKartsDownwards } //projectKartsDownwards
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Handles the special case of two karts colliding with each other, which means /** Handles the special case of two karts colliding with each other, which
* that bombs must be passed on. If both karts have a bomb, they'll explode * means that bombs must be passed on. If both karts have a bomb, they'll
* immediately. This function is called from physics::update() on the server * explode immediately. This function is called from physics::update() on the
* and if no networking is used, and from race_state on the client to replay * server and if no networking is used, and from race_state on the client to
* what happened on the server. * replay what happened on the server.
* \param kartA First kart involved in the collision. * \param kartA First kart involved in the collision.
* \param kartB Second kart involved in the collision. * \param kartB Second kart involved in the collision.
*/ */
@ -253,9 +282,10 @@ void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
* physics time step might miss some collisions (when more than one internal * physics time step might miss some collisions (when more than one internal
* time step was done, and the collision is added and removed). So this * time step was done, and the collision is added and removed). So this
* function stores all collisions in a list, which is then handled after the * function stores all collisions in a list, which is then handled after the
* actual physics timestep. This list only stores a collision, if it's not * actual physics timestep. This list only stores a collision if it's not
* already in the list, so a collisions which is reported more than once is * already in the list, so a collisions which is reported more than once is
* nevertheless only handled once. * nevertheless only handled once.
* The list of collision
* Parameters: see bullet documentation for details. * Parameters: see bullet documentation for details.
*/ */
btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies, btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
@ -292,6 +322,7 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
// FIXME: Must be a moving physics object // FIXME: Must be a moving physics object
// FIXME: A rocket should explode here! // FIXME: A rocket should explode here!
if(!upA || !upB) continue; if(!upA || !upB) continue;
// 1) object A is a track // 1) object A is a track
// ======================= // =======================
if(upA->is(UserPointer::UP_TRACK)) if(upA->is(UserPointer::UP_TRACK))
@ -324,28 +355,39 @@ btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
kart->crashed(NULL, m); // Kart hit track kart->crashed(NULL, m); // Kart hit track
} }
else if(upB->is(UserPointer::UP_FLYABLE)) else if(upB->is(UserPointer::UP_FLYABLE))
m_all_collisions.push_back(upB, upA); // 2.1 projectile hits kart // 2.1 projectile hits kart
m_all_collisions.push_back(upB, upA);
else if(upB->is(UserPointer::UP_KART)) else if(upB->is(UserPointer::UP_KART))
m_all_collisions.push_back(upA, upB); // 2.2 kart hits kart // 2.2 kart hits kart
m_all_collisions.push_back(upA, upB);
else if(upB->is(UserPointer::UP_PHYSICAL_OBJECT))
// 2.3 kart hits physical object
m_all_collisions.push_back(upB, upA);
} }
// 3) object is a projectile // 3) object is a projectile
// ========================= // =========================
else if(upA->is(UserPointer::UP_FLYABLE)) else if(upA->is(UserPointer::UP_FLYABLE))
{ {
if(upB->is(UserPointer::UP_TRACK ) || // 3.1) projectile hits track // 3.1) projectile hits track
upB->is(UserPointer::UP_FLYABLE ) || // 3.2) projectile hits projectile // 3.2) projectile hits projectile
upB->is(UserPointer::UP_PHYSICAL_OBJECT) || // 3.3) projectile hits projectile // 3.3) projectile hits physical object
upB->is(UserPointer::UP_KART ) ) // 3.4) projectile hits kart // 3.4) projectile hits kart
if(upB->is(UserPointer::UP_TRACK ) ||
upB->is(UserPointer::UP_FLYABLE ) ||
upB->is(UserPointer::UP_PHYSICAL_OBJECT) ||
upB->is(UserPointer::UP_KART ) )
{ {
m_all_collisions.push_back(upA, upB); m_all_collisions.push_back(upA, upB);
} }
} }
// Object is a physical object
// ===========================
else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT)) else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT))
{ {
if(upB->is(UserPointer::UP_FLYABLE)) if(upB->is(UserPointer::UP_FLYABLE))
{
m_all_collisions.push_back(upB, upA); m_all_collisions.push_back(upB, upA);
} else if(upB->is(UserPointer::UP_KART))
m_all_collisions.push_back(upA, upB);
} }
else assert("Unknown user pointer"); // 4) Should never happen else assert("Unknown user pointer"); // 4) Should never happen
} // for i<numManifolds } // for i<numManifolds