World.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright © 2009, 2010 James Legg.
00006     This program is free software: you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation, either version 3 of the License, or
00009     (at your option) any later version.
00010 */
00011 
00012 #include <fstream>
00013 
00014 #include "World.h"
00015 #include <Debug.h>
00016 #include "../InputHandler.h"
00017 #include "../Audio.h"
00018 
00019 namespace Engine
00020 {
00021 
00022 namespace Physics
00023 {
00024 
00025 const int milliseconds_per_tick = 12;
00026 const float seconds_per_tick = btScalar(milliseconds_per_tick) / btScalar(1000.0);
00027 /* Limit ticks so if physics takes longer to calculate than the time we are
00028  * simulating, we don't grind to a halt. The maximum amount of ticks should
00029  * be about enough to support 12 frames per second before slowing down the
00030  * simulation.
00031  */
00032 const unsigned int max_tick_count = 1000 / 12 / milliseconds_per_tick + 1;
00033 
00034 World::World(const Track::Track & track)
00035     :   m_track(track)
00036     ,   milliseconds_remaining(milliseconds_per_tick)
00037     ,   tick_number(1)
00038 {
00039     // create world stuff
00040     
00041     // maximum number of rigid bodies in the scene
00042     int maxProxies = 64;
00043     // maximum bounds of the scene for broadphase
00044     Track::AxisAlignedBoundingBox bounds = track.get_path().get_bounds();
00045     bounds.add_border(20.0);
00046     broadphase = new btAxisSweep3(bounds.get_min(), bounds.get_max(), maxProxies);
00047     // full collision detection
00048     collisionConfiguration = new btDefaultCollisionConfiguration();
00049     dispatcher = new btCollisionDispatcher(collisionConfiguration);
00050     // solver
00051     solver = new btSequentialImpulseConstraintSolver;
00052     // dynamics world
00053     dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
00054     dynamicsWorld->setGravity(btVector3(0,0,-0.98));
00055     
00056     /* Floor collision world, with only the surfaces from course_collision_world
00057      * you can drive on. Mostly usefult to Car, not us.
00058      * Use a different collision detection so only the floor is detected.
00059      */
00060     floor_broadphase = new btAxisSweep3(bounds.get_min(), bounds.get_max(), maxProxies);
00061     floor_collision_configuration = new btDefaultCollisionConfiguration();
00062     floor_dispatcher = new btCollisionDispatcher(collisionConfiguration);
00063     floor_world = new btCollisionWorld(floor_dispatcher, floor_broadphase, floor_collision_configuration);
00064     
00065     /* Reserve some space for replay data, so we aren't constantly reallocating
00066      * a large array.
00067      */
00068     replay_events.reserve(100 * 60 * 3 // 100 frames per second, for 3 minutes
00069                           * 4 * 3); // 4 cars, 3 inputs each per frame.
00070     // 3 is the maximum number of inputs per frame, may be far less on average.
00071     
00072 }
00073 
00074 World::~World()
00075 {
00076     delete dynamicsWorld;
00077     delete solver;
00078     delete collisionConfiguration;
00079     delete dispatcher;
00080     delete broadphase;
00081     
00082     delete floor_world;
00083     delete floor_broadphase;
00084     delete floor_collision_configuration;
00085     delete floor_dispatcher;
00086 }
00087 
00088 void World::update(unsigned int milliseconds_ellapsed)
00089 { 
00090     // milliseconds_remaining is the time in milliseconds that has passed but
00091     // hasn't been simulated yet.
00092     // Physics is done in fixed timesteps for determanism.
00093     // If there are left over milliseconds, we just leave them.
00094     milliseconds_remaining += milliseconds_ellapsed;
00095     while (milliseconds_remaining >= milliseconds_per_tick)
00096     {
00097         dynamicsWorld->stepSimulation(seconds_per_tick, 1, seconds_per_tick);
00098         
00099         // collision sounds
00100         int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
00101         for (int i=0;i<numManifolds;i++)
00102         {
00103             btPersistentManifold* contactManifold =  dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
00104             btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
00105             btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
00106         
00107             int numContacts = contactManifold->getNumContacts();
00108             for (int j=0;j<numContacts;j++)
00109             {
00110                 btManifoldPoint& pt = contactManifold->getContactPoint(j);
00111                 if (pt.getDistance()<0.f)
00112                 {
00113                     const btVector3& ptA = pt.getPositionWorldOnA();
00114                     const btVector3& ptB = pt.getPositionWorldOnB();
00115                     const btVector3& normalOnB = pt.m_normalWorldOnB;
00116                     static SoundBuffer sound_buffer("data/sound/collision.wav");
00117                     static SoundSource sound_source(sound_buffer);
00118                     sound_source.set_position(ptA);
00119                     sound_source.play();
00120                 }
00121             }
00122         }
00123         // check for input (some of the time so AI doesn't take so long).
00124         // input is additionaly checked by scenes once per rendered frame.
00125         if (!(tick_number % 4))
00126         {
00127             Engine::InputHandler::get_instance().poll();
00128         }
00129         // forces set in the tick callback don't seem to work, hence this
00130         // loop. Call pretick set the forces.
00131         for (std::set<TickObserver *>::iterator it = observers.begin();
00132              it != observers.end();
00133              it++)
00134         {
00135             (*it)->posttick();
00136             (*it)->set_forces();
00137         }
00138         tick_number++;
00139         milliseconds_remaining -= milliseconds_per_tick;
00140     }
00141 }
00142 
00143 btDiscreteDynamicsWorld & World::get_dynamics_world()
00144 {
00145     return *dynamicsWorld;
00146 }
00147 
00148 btCollisionWorld & World::get_floor_world()
00149 {
00150     return *floor_world;
00151 }
00152 
00153 void World::add_tick_observer(TickObserver * tick_observer)
00154 {
00155     observers.insert(tick_observer);
00156 }
00157 
00158 void World::remove_tick_observer(TickObserver * tick_observer)
00159 {
00160     observers.erase(tick_observer);
00161 }
00162 
00163 void World::add_replay_report(const InputReport & report)
00164 {
00165     switch (report.get_report_type())
00166     {
00167         case InputReport::RT_MENU_BACK:
00168         case InputReport::RT_MENU_DOWN:
00169         case InputReport::RT_MENU_LEFT:
00170         case InputReport::RT_MENU_RIGHT:
00171         case InputReport::RT_MENU_SELECT:
00172         case InputReport::RT_MENU_UP:
00173         case InputReport::RT_DISCONNECT:
00174         case InputReport::RT_BATTERY_LOW:
00175             // don't record menu inputs or anything else that doesn't affect physics.
00176             break;
00177         default:
00178             // record other inputs.
00179             replay_events.push_back(ReplayEvent(tick_number, report));
00180     }
00181 }
00182 
00183 World::ReplayEvent::ReplayEvent(unsigned long int tick_number,
00184                                 const InputReport & report)
00185     :   tick_number(tick_number)
00186     ,   report(report)
00187 {
00188 }
00189 
00190 
00191 void World::write_replay_events(std::ostream & stream)
00192 {
00193     // record replay to file.
00195 
00198     DEBUG_MESSAGE("Writing replay");
00199     for (std::vector<ReplayEvent>::iterator it = replay_events.begin();
00200          it != replay_events.end(); it++)
00201     {
00202         const ReplayEvent & event = *it;
00203         const InputReport & report = event.report;
00204         stream << event.tick_number << " "
00205                << (unsigned long int)&*(report.get_input_device()) << " "
00206                << report.get_report_type() << " "
00207                << report.get_value() << " ";
00208     }
00209 }
00210 
00211 unsigned long int World::get_tick_number()
00212 {
00213     return tick_number;
00214 }
00215 
00216 const Track::Track & World::get_track()
00217 {
00218     return m_track;
00219 }
00220 
00221 }
00222 
00223 }

Get Racer at SourceForge.net. Fast, secure and Free Open Source software downloads

Generated at Mon Sep 6 00:41:12 2010 by Doxygen version 1.4.7 for Racer version svn335.