Back to index

supertuxkart  0.5+dfsg1
physics.cpp
Go to the documentation of this file.
00001 //  $Id: physics.cpp 839 2006-10-24 00:01:56Z hiker $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2006 Joerg Henrichs
00005 //
00006 //  This program is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU General Public License
00008 //  as published by the Free Software Foundation; either version 2
00009 //  of the License, or (at your option) any later version.
00010 //
00011 //  This program is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty ofati
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020 #include "physics.hpp"
00021 #include "ssg_help.hpp"
00022 #include "world.hpp"
00023 #include "flyable.hpp"
00024 
00025 #include "moving_physics.hpp"
00026 #include "user_config.hpp"
00027 #include "sound_manager.hpp"
00028 #include "material_manager.hpp"
00029 
00031 // ----------------------------------------------------------------------------
00032 
00033 Physics::Physics(float gravity) : btSequentialImpulseConstraintSolver()
00034 {
00035     m_collision_conf    = new btDefaultCollisionConfiguration();
00036     m_dispatcher        = new btCollisionDispatcher(m_collision_conf);
00037     
00038     btVector3 worldMin(-1000, -1000, -1000);
00039     btVector3 worldMax( 1000,  1000,  1000);
00040     m_axis_sweep        = new btAxisSweep3(worldMin, worldMax);
00041     m_dynamics_world    = new btDiscreteDynamicsWorld(m_dispatcher, 
00042                                                       m_axis_sweep, 
00043                                                       this,
00044                                                       m_collision_conf);
00045     m_dynamics_world->setGravity(btVector3(0.0f, 0.0f, -gravity));
00046     if(user_config->m_bullet_debug)
00047     {
00048         m_debug_drawer=new GLDebugDrawer();
00049         m_debug_drawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
00050         m_dynamics_world->setDebugDrawer(m_debug_drawer);
00051     }
00052 }   // Physics
00053 
00054 //-----------------------------------------------------------------------------
00055 Physics::~Physics()
00056 {
00057     if(user_config->m_bullet_debug) delete m_debug_drawer;
00058     delete m_dynamics_world;
00059     delete m_axis_sweep;
00060     delete m_dispatcher;
00061     delete m_collision_conf;
00062     
00063 }   // ~Physics
00064 
00065 // -----------------------------------------------------------------------------
00066 //* Adds a kart to the physics engine
00067 void Physics::addKart(const Kart *kart, btRaycastVehicle *vehicle)
00068 {
00069     m_dynamics_world->addRigidBody(kart->getBody());
00070     m_dynamics_world->addVehicle(vehicle);
00071     m_dynamics_world->addConstraint(kart->getUprightConstraint());
00072 }   // addKart
00073 
00074 //-----------------------------------------------------------------------------
00078 void Physics::removeKart(const Kart *kart)
00079 {
00080     m_dynamics_world->removeRigidBody(kart->getBody());
00081     m_dynamics_world->removeVehicle(kart->getVehicle());
00082     m_dynamics_world->removeConstraint(kart->getUprightConstraint());
00083 }   // removeKart
00084 
00085 //-----------------------------------------------------------------------------
00086 void Physics::update(float dt)
00087 {
00088     // Bullet can report the same collision more than once (up to 4 
00089     // contact points per collision. Additionally, more than one internal
00090     // substep might be taken, resulting in potentially even more 
00091     // duplicates. To handle this, all collisions (i.e. pair of objects)
00092     // are stored in a vector, but only one entry per collision pair
00093     // of objects.
00094     m_all_collisions.clear();
00095 
00096     // Maximum of three substeps. This will work for framerate down to
00097     // 20 FPS (bullet default frequency is 60 HZ).
00098     m_dynamics_world->stepSimulation(dt, 3);
00099 
00100     // Now handle the actual collision. Note: rockets can not be removed
00101     // inside of this loop, since the same rocket might hit more than one
00102     // other object. So, only a flag is set in the rockets, the actual
00103     // clean up is then done later in the projectile manager.
00104     std::vector<CollisionPair>::iterator p;
00105     for(p=m_all_collisions.begin(); p!=m_all_collisions.end(); ++p)
00106     {
00107         if(p->a->is(UserPointer::UP_KART)) {          // kart-kart collision
00108             KartKartCollision(p->a->getPointerKart(), p->b->getPointerKart());
00109         }  // if kart-kart collision
00110         else  // now the first object must be a projectile
00111         {
00112             if(p->b->is(UserPointer::UP_TRACK))       // must be projectile hit track
00113             {
00114                 p->a->getPointerFlyable()->hitTrack();
00115             }
00116             else if(p->b->is(UserPointer::UP_MOVING_PHYSICS))
00117             {
00118                 p->a->getPointerFlyable()->explode(NULL, p->b->getPointerMovingPhysics());
00119 
00120             }
00121             else if(p->b->is(UserPointer::UP_KART))   // projectile hit kart
00122             {
00123                 p->a->getPointerFlyable()->explode(p->b->getPointerKart());
00124             }
00125             else                                     // projectile hits projectile
00126             {
00127                 p->a->getPointerFlyable()->explode(NULL);
00128                 p->b->getPointerFlyable()->explode(NULL);
00129             }
00130         }
00131     }  // for all p in m_all_collisions
00132 }   // update
00133 
00134 //-----------------------------------------------------------------------------
00138 void Physics::KartKartCollision(Kart *kartA, Kart *kartB)
00139 {
00140     kartA->crashed();   // will play crash sound for player karts
00141     kartB->crashed(); 
00142     Attachment *attachmentA=kartA->getAttachment();
00143     Attachment *attachmentB=kartB->getAttachment();
00144 
00145     if(attachmentA->getType()==ATTACH_BOMB)
00146     {
00147         // If both karts have a bomb, explode them immediately:
00148         if(attachmentB->getType()==ATTACH_BOMB)
00149         {
00150             attachmentA->setTimeLeft(0.0f);
00151             attachmentB->setTimeLeft(0.0f);
00152         } 
00153         else  // only A has a bomb, move it to B (unless it was from B)
00154         {
00155             if(attachmentA->getPreviousOwner()!=kartB) 
00156             {
00157                 attachmentA->moveBombFromTo(kartA, kartB);
00158             }
00159         }
00160     }
00161     else if(attachmentB->getType()==ATTACH_BOMB &&
00162         attachmentB->getPreviousOwner()!=kartA) 
00163     {
00164         attachmentB->moveBombFromTo(kartB, kartA);
00165     }
00166 }   // KartKartCollision
00167 
00168 //-----------------------------------------------------------------------------
00174 btScalar Physics::solveGroup(btCollisionObject** bodies, int numBodies,
00175                              btPersistentManifold** manifold,int numManifolds,
00176                              btTypedConstraint** constraints,int numConstraints,
00177                              const btContactSolverInfo& info, 
00178                              btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc,
00179                              btDispatcher* dispatcher) {
00180     btScalar returnValue=
00181         btSequentialImpulseConstraintSolver::solveGroup(bodies, numBodies, manifold, 
00182                                                         numManifolds, constraints, 
00183                                                         numConstraints, info, 
00184                                                         debugDrawer, stackAlloc,
00185                                                         dispatcher);
00186     int currentNumManifolds = m_dispatcher->getNumManifolds();
00187     // We can't explode a rocket in a loop, since a rocket might collide with 
00188     // more than one object, and/or more than once with each object (if there 
00189     // is more than one collision point). So keep a list of rockets that will
00190     // be exploded after the collisions
00191     std::vector<Moveable*> rocketsToExplode;
00192     for(int i=0; i<currentNumManifolds; i++)
00193     {               
00194         btPersistentManifold* contactManifold = m_dynamics_world->getDispatcher()->getManifoldByIndexInternal(i);
00195 
00196         btCollisionObject* objA = static_cast<btCollisionObject*>(contactManifold->getBody0());
00197         btCollisionObject* objB = static_cast<btCollisionObject*>(contactManifold->getBody1());
00198         
00199         int numContacts = contactManifold->getNumContacts();
00200         if(!numContacts) continue;   // no real collision
00201 
00202         UserPointer *upA        = (UserPointer*)(objA->getUserPointer());
00203         UserPointer *upB        = (UserPointer*)(objB->getUserPointer());
00204 
00205         // FIXME: Must be a moving physics object
00206         // FIXME: A rocket should explode here!
00207 
00208         if(!upA || !upB) continue;
00209         // 1) object A is a track
00210         // =======================
00211         if(upA->is(UserPointer::UP_TRACK)) 
00212         { 
00213             if(upB->is(UserPointer::UP_FLYABLE))   // 1.1 projectile hits track
00214                 m_all_collisions.push_back(upB, upA);
00215             else if(upB->is(UserPointer::UP_KART))
00216                 // FIXME: sound disabled for now, since the chassis of the karts hits
00217                 //        the track when accelerating, causing a constant crash sfx
00218                 //        to be played. Might be fixed with better physics parameters
00219                 //upB->getPointerKart()->crashed();
00220 #if defined(WIN32) && !defined(__CYGWIN__)
00221                 0  // avoid VS compiler warning while the above statement is commented out
00222 #endif
00223                  ;
00224         }
00225         // 2) object a is a kart
00226         // =====================
00227         else if(upA->is(UserPointer::UP_KART))
00228         {
00229             if(upB->is(UserPointer::UP_TRACK))
00230                 // FIXME: sound disabled for now, since the chassis of the karts hits
00231                 //        the track when accelerating, causing a constant crash sfx
00232                 //        to be played. Might be fixed with better physics parameters
00233                 // upA->getPointerKart()->crashed(); // Kart hit track
00234                 ;
00235             else if(upB->is(UserPointer::UP_FLYABLE))
00236                 m_all_collisions.push_back(upB, upA);   // 2.1 projectile hits kart
00237             else if(upB->is(UserPointer::UP_KART))
00238                 m_all_collisions.push_back(upA, upB);   // 2.2 kart hits kart
00239         }
00240         // 3) object is a projectile
00241         // ========================
00242         else if(upA->is(UserPointer::UP_FLYABLE))
00243         {
00244             if(upB->is(UserPointer::UP_TRACK         ) ||   // 3.1) projectile hits track
00245                upB->is(UserPointer::UP_FLYABLE       ) ||   // 3.2) projectile hits projectile
00246                upB->is(UserPointer::UP_MOVING_PHYSICS) ||   // 3.3) projectile hits projectile
00247                upB->is(UserPointer::UP_KART          )   )  // 3.4) projectile hits kart
00248             {
00249                 m_all_collisions.push_back(upA, upB);
00250             }
00251         } 
00252         else if(upA->is(UserPointer::UP_MOVING_PHYSICS))
00253         {
00254             if(upB->is(UserPointer::UP_FLYABLE)) 
00255             {
00256                 m_all_collisions.push_back(upB, upA);
00257             }
00258         }
00259         else assert("Unknown user pointer");            // 4) Should never happen
00260     }   // for i<numManifolds
00261 
00262     return returnValue;
00263 }   // solveGroup
00264 
00265 // -----------------------------------------------------------------------------
00266 void Physics::draw()
00267 {
00268     if(user_config->m_bullet_debug)
00269     {
00270         int num_objects = m_dynamics_world->getNumCollisionObjects();
00271         for(int i=0; i<num_objects; i++)
00272         {
00273             btCollisionObject *obj = m_dynamics_world->getCollisionObjectArray()[i];
00274             btRigidBody* body = btRigidBody::upcast(obj);
00275             if(!body) continue;
00276             float m[16];
00277             btVector3 wireColor(1,0,0);
00278             btDefaultMotionState *myMotion = (btDefaultMotionState*)body->getMotionState();
00279             if(myMotion) 
00280             {
00281                 myMotion->m_graphicsWorldTrans.getOpenGLMatrix(m);
00282                 debugDraw(m, obj->getCollisionShape(), wireColor);
00283             }
00284         }  // for i
00285     }   // if m_bullet_debug
00286 }   // draw
00287 
00288 // -----------------------------------------------------------------------------
00289 void Physics::debugDraw(float m[16], btCollisionShape *s, const btVector3 color)
00290     
00291 {
00292     m_shape_drawer.drawOpenGL(m, s, color, 0);
00293     //                               btIDebugDraw::DBG_DrawWireframe);
00294     //                               btIDebugDraw::DBG_DrawAabb);
00295 
00296 }   // debugDraw
00297 // -----------------------------------------------------------------------------
00298 
00299 /* EOF */
00300