2007-05-27 12:01:53 -04:00
|
|
|
// $Id: physics.cpp 839 2006-10-24 00:01:56Z hiker $
|
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
|
|
// Copyright (C) 2006 Joerg Henrichs
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
2007-11-03 09:13:26 -04:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty ofati
|
2007-05-27 12:01:53 -04:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
#include "bullet/Demos/OpenGL/GL_ShapeDrawer.h"
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
#include "physics.hpp"
|
|
|
|
#include "ssg_help.hpp"
|
|
|
|
#include "world.hpp"
|
2007-12-08 08:04:56 -05:00
|
|
|
#include "flyable.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
#include "moving_physics.hpp"
|
|
|
|
#include "user_config.hpp"
|
2007-11-03 09:13:26 -04:00
|
|
|
#include "sound_manager.hpp"
|
2007-11-08 07:31:54 -05:00
|
|
|
#include "material_manager.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
/** Initialise physics. */
|
2007-12-12 09:07:26 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
2007-11-03 09:13:26 -04:00
|
|
|
|
2007-12-08 08:04:56 -05:00
|
|
|
Physics::Physics(float gravity) : btSequentialImpulseConstraintSolver()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2007-11-08 07:31:54 -05:00
|
|
|
m_collision_conf = new btDefaultCollisionConfiguration();
|
|
|
|
m_dispatcher = new btCollisionDispatcher(m_collision_conf);
|
2007-11-03 09:13:26 -04:00
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
btVector3 worldMin(-1000, -1000, -1000);
|
|
|
|
btVector3 worldMax( 1000, 1000, 1000);
|
2007-11-08 07:31:54 -05:00
|
|
|
m_axis_sweep = new btAxisSweep3(worldMin, worldMax);
|
|
|
|
m_dynamics_world = new btDiscreteDynamicsWorld(m_dispatcher,
|
|
|
|
m_axis_sweep,
|
2007-12-08 08:04:56 -05:00
|
|
|
this,
|
2007-11-08 07:31:54 -05:00
|
|
|
m_collision_conf);
|
2007-05-27 12:01:53 -04:00
|
|
|
m_dynamics_world->setGravity(btVector3(0.0f, 0.0f, -gravity));
|
|
|
|
if(user_config->m_bullet_debug)
|
|
|
|
{
|
|
|
|
m_debug_drawer=new GLDebugDrawer();
|
|
|
|
m_debug_drawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
|
|
|
|
m_dynamics_world->setDebugDrawer(m_debug_drawer);
|
|
|
|
}
|
|
|
|
} // Physics
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Physics::~Physics()
|
|
|
|
{
|
2007-12-08 08:04:56 -05:00
|
|
|
if(user_config->m_bullet_debug) delete m_debug_drawer;
|
2007-05-27 12:01:53 -04:00
|
|
|
delete m_dynamics_world;
|
2007-11-08 07:31:54 -05:00
|
|
|
delete m_axis_sweep;
|
2007-12-08 08:04:56 -05:00
|
|
|
delete m_dispatcher;
|
2007-11-08 07:31:54 -05:00
|
|
|
delete m_collision_conf;
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
} // ~Physics
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//* Adds a kart to the physics engine
|
|
|
|
void Physics::addKart(const Kart *kart, btRaycastVehicle *vehicle)
|
|
|
|
{
|
2007-09-30 10:17:28 -04:00
|
|
|
m_dynamics_world->addRigidBody(kart->getBody());
|
2007-05-27 12:01:53 -04:00
|
|
|
m_dynamics_world->addVehicle(vehicle);
|
|
|
|
|
|
|
|
} // addKart
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2007-11-03 09:13:26 -04:00
|
|
|
/** Removes a kart from the physics engine. This is used when rescuing a kart
|
|
|
|
* (and during cleanup).
|
2007-05-27 12:01:53 -04:00
|
|
|
*/
|
2007-11-03 09:13:26 -04:00
|
|
|
void Physics::removeKart(const Kart *kart)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2007-09-30 10:17:28 -04:00
|
|
|
m_dynamics_world->removeRigidBody(kart->getBody());
|
2007-11-03 09:13:26 -04:00
|
|
|
m_dynamics_world->removeVehicle(kart->getVehicle());
|
2007-05-27 12:01:53 -04:00
|
|
|
} // removeKart
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void Physics::update(float dt)
|
|
|
|
{
|
2007-12-08 08:04:56 -05:00
|
|
|
// Bullet can report the same collision more than once (up to 4
|
|
|
|
// 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
|
|
|
|
// of objects.
|
|
|
|
m_all_collisions.clear();
|
2007-05-27 12:01:53 -04:00
|
|
|
m_dynamics_world->stepSimulation(dt);
|
2007-12-08 08:04:56 -05:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// 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->type_a==Moveable::MOV_KART) { // kart-kart collision
|
|
|
|
Kart *kartA = (Kart*)(p->a);
|
|
|
|
Kart *kartB = (Kart*)(p->b);
|
|
|
|
KartKartCollision(kartA, kartB);
|
|
|
|
} // if kart-kart collision
|
|
|
|
else // now the first object must be a projectile
|
|
|
|
{
|
|
|
|
if(p->type_b==Moveable::MOV_TRACK) // must be projectile hit track
|
|
|
|
{
|
|
|
|
((Flyable*)(p->a))->hitTrack();
|
|
|
|
}
|
|
|
|
else if(p->type_b==Moveable::MOV_KART) // projectile hit kart
|
|
|
|
{
|
|
|
|
Flyable *f=(Flyable*)(p->a);
|
|
|
|
f->explode((Kart*)(p->b));
|
|
|
|
}
|
|
|
|
else // projectile hits projectile
|
|
|
|
{
|
|
|
|
((Flyable*)(p->a))->explode(NULL);
|
|
|
|
((Flyable*)(p->b))->explode(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // for all p in m_all_collisions
|
2007-05-27 12:01:53 -04:00
|
|
|
} // update
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
/** Handles the special case of two karts colliding with each other
|
|
|
|
* If both karts have a bomb, they'll explode immediately
|
|
|
|
*/
|
|
|
|
void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
|
|
|
|
{
|
|
|
|
Attachment *attachmentA=kartA->getAttachment();
|
|
|
|
Attachment *attachmentB=kartB->getAttachment();
|
|
|
|
|
|
|
|
if(attachmentA->getType()==ATTACH_BOMB)
|
|
|
|
{
|
|
|
|
// If both karts have a bomb, explode them immediately:
|
|
|
|
if(attachmentB->getType()==ATTACH_BOMB)
|
|
|
|
{
|
|
|
|
attachmentA->setTimeLeft(0.0f);
|
|
|
|
attachmentB->setTimeLeft(0.0f);
|
|
|
|
}
|
|
|
|
else // only A has a bomb, move it to B (unless it was from B)
|
|
|
|
{
|
|
|
|
if(attachmentA->getPreviousOwner()!=kartB)
|
|
|
|
{
|
|
|
|
attachmentA->moveBombFromTo(kartA, kartB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(attachmentB->getType()==ATTACH_BOMB &&
|
|
|
|
attachmentB->getPreviousOwner()!=kartA)
|
|
|
|
{
|
|
|
|
attachmentB->moveBombFromTo(kartB, kartA);
|
|
|
|
}
|
|
|
|
if(kartA->isPlayerKart()) sound_manager->playSfx(SOUND_CRASH);
|
|
|
|
if(kartB->isPlayerKart()) sound_manager->playSfx(SOUND_CRASH);
|
|
|
|
|
|
|
|
} // KartKartCollision
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** This function is called at each internal bullet timestep. It is used
|
|
|
|
* here to do the collision handling: using the contact manifolds after a
|
|
|
|
* physics time step might miss some collisions (when more than one internal
|
|
|
|
* time step was done, and the collision is added and removed).
|
|
|
|
**/
|
|
|
|
btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
|
|
|
|
btPersistentManifold** manifold,int numManifolds,
|
|
|
|
btTypedConstraint** constraints,int numConstraints,
|
|
|
|
const btContactSolverInfo& info,
|
|
|
|
btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc,
|
|
|
|
btDispatcher* dispatcher) {
|
|
|
|
btScalar returnValue=
|
|
|
|
btSequentialImpulseConstraintSolver::solveGroup(bodies, numBodies, manifold,
|
|
|
|
numManifolds, constraints,
|
|
|
|
numConstraints, info,
|
|
|
|
debugDrawer, stackAlloc,
|
|
|
|
dispatcher);
|
|
|
|
int currentNumManifolds = m_dispatcher->getNumManifolds();
|
|
|
|
// We can't explode a rocket in a loop, since a rocket might collide with
|
|
|
|
// more than one object, and/or more than once with each object (if there
|
|
|
|
// is more than one collision point). So keep a list of rockets that will
|
|
|
|
// be exploded after the collisions
|
|
|
|
std::vector<Moveable*> rocketsToExplode;
|
|
|
|
for(int i=0; i<currentNumManifolds; i++)
|
2007-11-03 09:13:26 -04:00
|
|
|
{
|
|
|
|
btPersistentManifold* contactManifold = m_dynamics_world->getDispatcher()->getManifoldByIndexInternal(i);
|
|
|
|
|
|
|
|
btCollisionObject* objA = static_cast<btCollisionObject*>(contactManifold->getBody0());
|
|
|
|
btCollisionObject* objB = static_cast<btCollisionObject*>(contactManifold->getBody1());
|
|
|
|
|
|
|
|
int numContacts = contactManifold->getNumContacts();
|
|
|
|
if(!numContacts) continue; // no real collision
|
|
|
|
|
|
|
|
Moveable *movA = static_cast<Moveable*>(objA->getUserPointer());
|
|
|
|
Moveable *movB = static_cast<Moveable*>(objB->getUserPointer());
|
|
|
|
|
2007-12-08 08:04:56 -05:00
|
|
|
if(!numContacts) continue; // no real collision
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
// 1) object A is a track
|
|
|
|
// =======================
|
|
|
|
if(!movA)
|
|
|
|
{
|
2007-12-08 08:04:56 -05:00
|
|
|
if(movB && movB->getMoveableType()==Moveable::MOV_PROJECTILE)
|
|
|
|
{ // 1.1 projectile hits track
|
2007-11-03 09:13:26 -04:00
|
|
|
// -------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movB, Moveable::MOV_PROJECTILE,
|
|
|
|
NULL, Moveable::MOV_TRACK ));
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 2) object a is a kart
|
|
|
|
// =====================
|
|
|
|
else if(movA->getMoveableType()==Moveable::MOV_KART)
|
|
|
|
{
|
2007-12-08 08:04:56 -05:00
|
|
|
if(movB && movB->getMoveableType()==Moveable::MOV_PROJECTILE)
|
|
|
|
{ // 2.1 projectile hits kart
|
2007-11-03 09:13:26 -04:00
|
|
|
// -------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movB, Moveable::MOV_PROJECTILE,
|
|
|
|
movA, Moveable::MOV_KART ));
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
2007-12-08 08:04:56 -05:00
|
|
|
else if(movB && movB->getMoveableType()==Moveable::MOV_KART)
|
|
|
|
{ // 2.2 kart hits kart
|
2007-11-03 09:13:26 -04:00
|
|
|
// ------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movA, Moveable::MOV_KART,
|
|
|
|
movB, Moveable::MOV_KART ));
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 3) object is a projectile
|
|
|
|
// ========================
|
|
|
|
else if(movA->getMoveableType()==Moveable::MOV_PROJECTILE)
|
|
|
|
{
|
|
|
|
if(!movB)
|
|
|
|
{ // 3.1) projectile hits track
|
|
|
|
// --------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movA, Moveable::MOV_PROJECTILE,
|
|
|
|
NULL, Moveable::MOV_TRACK ));
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
|
|
|
else if(movB->getMoveableType()==Moveable::MOV_PROJECTILE)
|
|
|
|
{ // 3.2 projectile hits projectile
|
|
|
|
// ------------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movA, Moveable::MOV_PROJECTILE,
|
|
|
|
movB, Moveable::MOV_PROJECTILE));
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
|
|
|
else if(movB->getMoveableType()==Moveable::MOV_KART)
|
|
|
|
{ // 3.3 projectile hits kart
|
|
|
|
// ------------------------
|
2007-12-08 08:04:56 -05:00
|
|
|
m_all_collisions.push_back(CollisionPair(movA, Moveable::MOV_PROJECTILE,
|
|
|
|
movB, Moveable::MOV_KART ));
|
2007-11-03 09:13:26 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 4) Nothing else should happen
|
|
|
|
// =============================
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert("Unknown user pointer");
|
|
|
|
}
|
|
|
|
} // for i<numManifolds
|
2007-12-08 08:04:56 -05:00
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
} // solveGroup
|
2007-11-03 09:13:26 -04:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2007-05-27 12:01:53 -04:00
|
|
|
void Physics::draw()
|
|
|
|
{
|
|
|
|
if(user_config->m_bullet_debug)
|
|
|
|
{
|
|
|
|
int num_objects = m_dynamics_world->getNumCollisionObjects();
|
|
|
|
for(int i=0; i<num_objects; i++)
|
|
|
|
{
|
|
|
|
btCollisionObject *obj = m_dynamics_world->getCollisionObjectArray()[i];
|
|
|
|
btRigidBody* body = btRigidBody::upcast(obj);
|
|
|
|
if(!body) continue;
|
|
|
|
float m[16];
|
|
|
|
btVector3 wireColor(1,0,0);
|
|
|
|
btDefaultMotionState *myMotion = (btDefaultMotionState*)body->getMotionState();
|
|
|
|
if(myMotion)
|
|
|
|
{
|
|
|
|
myMotion->m_graphicsWorldTrans.getOpenGLMatrix(m);
|
|
|
|
debugDraw(m, obj->getCollisionShape(), wireColor);
|
|
|
|
}
|
|
|
|
} // for i
|
|
|
|
} // if m_bullet_debug
|
|
|
|
} // draw
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void Physics::debugDraw(float m[16], btCollisionShape *s, const btVector3 color)
|
|
|
|
|
|
|
|
{
|
|
|
|
GL_ShapeDrawer::drawOpenGL(m, s, color, 0);
|
|
|
|
// btIDebugDraw::DBG_DrawWireframe);
|
|
|
|
// btIDebugDraw::DBG_DrawAabb);
|
|
|
|
|
|
|
|
} // debugDraw
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/* EOF */
|
|
|
|
|