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_mass = 1;
m_radius = -1;
m_crash_reset = false;
std::string shape;
xml_node.get("mass", &m_mass );
xml_node.get("radius", &m_radius);
xml_node.get("shape", &shape );
xml_node.get("mass", &m_mass );
xml_node.get("radius", &m_radius );
xml_node.get("shape", &shape );
xml_node.get("reset", &m_crash_reset);
m_body_type = MP_NONE;
if (shape=="cone" ||

View File

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

View File

@ -25,6 +25,7 @@
#include "physics/btKart.hpp"
#include "physics/btUprightConstraint.hpp"
#include "physics/irr_debug_drawer.hpp"
#include "physics/physical_object.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
@ -99,7 +100,7 @@ void Physics::removeKart(const Kart *kart)
void Physics::update(float dt)
{
// 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
// duplicates. To handle this, all collisions (i.e. pair of objects)
// are stored in a vector, but only one entry per collision pair
@ -110,45 +111,72 @@ void Physics::update(float dt)
// 20 FPS (bullet default frequency is 60 HZ).
m_dynamics_world->stepSimulation(dt, 3);
// Now handle the actual collision. Note: rockets can not be removed
// inside of this loop, since the same rocket might hit more than one
// other object. So, only a flag is set in the rockets, the actual
// Now handle the actual collision. Note: flyables can not be removed
// inside of this loop, since the same flyables might hit more than one
// other object. So only a flag is set in the flyables, the actual
// clean up is then done later in the projectile manager.
std::vector<CollisionPair>::iterator 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 *b=p->b->getPointerKart();
race_state->addCollision(a->getWorldKartId(),
b->getWorldKartId());
KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart());
continue;
} // if kart-kart collision
else // now the first object must be a projectile
{
if(p->b->is(UserPointer::UP_TRACK)) // must be projectile hit track
{
p->a->getPointerFlyable()->hitTrack();
}
else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT))
{
p->a->getPointerFlyable()->hit(NULL, p->b->getPointerPhysicalObject());
}
else if(p->b->is(UserPointer::UP_KART)) // projectile hit kart
if(p->a->is(UserPointer::UP_PHYSICAL_OBJECT))
{
// Kart hits physical object
// -------------------------
PhysicalObject *obj = p->a->getPointerPhysicalObject();
if(obj->isCrashReset())
{
// Only explode a bowling ball if the target is
// not invulnerable
if(p->a->getPointerFlyable()->getType()
!=PowerupManager::POWERUP_BOWLING ||
!p->b->getPointerKart()->isInvulnerable() )
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();
}
else if(p->b->is(UserPointer::UP_PHYSICAL_OBJECT))
{
// Projectile hits physical object
// -------------------------------
p->a->getPointerFlyable()
->hit(NULL, p->b->getPointerPhysicalObject());
}
else if(p->b->is(UserPointer::UP_KART))
{
// Projectile hits kart
// --------------------
// Only explode a bowling ball if the target is
// not invulnerable
if(p->a->getPointerFlyable()->getType()
!=PowerupManager::POWERUP_BOWLING ||
!p->b->getPointerKart()->isInvulnerable() )
p->a->getPointerFlyable()->hit(p->b->getPointerKart());
}
else // projectile hits projectile
{
p->a->getPointerFlyable()->hit(NULL);
p->b->getPointerFlyable()->hit(NULL);
}
}
else
{
// Projectile hits projectile
// --------------------------
p->a->getPointerFlyable()->hit(NULL);
p->b->getPointerFlyable()->hit(NULL);
}
} // for all p in m_all_collisions
} // update
@ -161,15 +189,16 @@ void Physics::update(float dt)
bool Physics::projectKartDownwards(const Kart *k)
{
btVector3 hell(0, -10000, 0);
return k->getVehicle()->projectVehicleToSurface(hell, true /*allow translation*/);
return k->getVehicle()->projectVehicleToSurface(hell,
/*allow translation*/true);
} //projectKartsDownwards
//-----------------------------------------------------------------------------
/** Handles the special case of two karts colliding with each other, which means
* that bombs must be passed on. If both karts have a bomb, they'll explode
* immediately. This function is called from physics::update() on the server
* and if no networking is used, and from race_state on the client to replay
* what happened on the server.
/** Handles the special case of two karts colliding with each other, which
* means that bombs must be passed on. If both karts have a bomb, they'll
* explode immediately. This function is called from physics::update() on the
* server and if no networking is used, and from race_state on the client to
* replay what happened on the server.
* \param kartA First 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
* 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
* 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
* nevertheless only handled once.
* The list of collision
* Parameters: see bullet documentation for details.
*/
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: A rocket should explode here!
if(!upA || !upB) continue;
// 1) object A is a 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
}
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))
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
// =========================
else if(upA->is(UserPointer::UP_FLYABLE))
{
if(upB->is(UserPointer::UP_TRACK ) || // 3.1) projectile hits track
upB->is(UserPointer::UP_FLYABLE ) || // 3.2) projectile hits projectile
upB->is(UserPointer::UP_PHYSICAL_OBJECT) || // 3.3) projectile hits projectile
upB->is(UserPointer::UP_KART ) ) // 3.4) projectile hits kart
// 3.1) projectile hits track
// 3.2) projectile hits projectile
// 3.3) projectile hits physical object
// 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);
}
}
// Object is a physical object
// ===========================
else if(upA->is(UserPointer::UP_PHYSICAL_OBJECT))
{
if(upB->is(UserPointer::UP_FLYABLE))
{
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
} // for i<numManifolds