00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "game.h"
00022 #include "gameprivate.h"
00023 #include "scene.h"
00024 #include "gameobject.h"
00025 #include "gameproject.h"
00026
00027 #include "core/debughelper.h"
00028
00029 #include <QtCore/QCoreApplication>
00030 #include <QtCore/QThread>
00031 #include <QtCore/QTime>
00032 #include <QtCore/QDebug>
00033
00034 #include <cstdlib>
00035 #include <ctime>
00036
00037 using namespace GluonEngine;
00038
00039 template<> Game* GluonCore::Singleton<Game>::m_instance = 0;
00040
00041 Game::Game( QObject* parent )
00042 {
00043 Q_UNUSED( parent );
00044 d = new GamePrivate;
00045
00046 srand( std::time( NULL ) );
00047 }
00048
00049 Game::~Game()
00050 {
00051 if( d->gameRunning )
00052 stopGame();
00053 }
00054
00055 int
00056 Game::getCurrentTick()
00057 {
00058 return d->time.elapsed();
00059 }
00060
00061 void
00062 Game::runGameFixedUpdate( int updatesPerSecond, int maxFrameSkip )
00063 {
00064 DEBUG_FUNC_NAME
00065
00066 if( !d->currentScene )
00067 {
00068 DEBUG_TEXT( QString( "There is no scene to run!" ) );
00069 return;
00070 }
00071
00072 int millisecondsPerUpdate = 1000 / updatesPerSecond;
00073 DEBUG_TEXT( QString( "Running the game using fixed update at %1 updates per second (meaning %2 milliseconds between each update, and drawing as often as possible, with a maximum of %3 frames skipped before forcing a draw)" ).arg( updatesPerSecond ).arg( millisecondsPerUpdate ).arg( maxFrameSkip ) );
00074
00075 int nextTick = 0, loops = 0;
00076 int timeLapse = 0;
00077 d->time.start();
00078
00079 d->gameRunning = true;
00080
00081 initializeAll();
00082
00083 startAll();
00084 while( d->gameRunning )
00085 {
00086
00087 QCoreApplication::processEvents();
00088
00089 if( d->resetScene )
00090 {
00091 stopAll();
00092 cleanupAll();
00093
00094 d->currentScene->resetScene();
00095
00096 initializeAll();
00097 startAll();
00098
00099 d->resetScene = false;
00100 emit currentSceneChanged( d->currentScene );
00101 }
00102
00103
00104
00105 loops = 0;
00106 while( getCurrentTick() > nextTick && loops < maxFrameSkip )
00107 {
00108 if( !d->gamePaused )
00109 {
00110 updateAll( millisecondsPerUpdate );
00111 }
00112 nextTick += millisecondsPerUpdate;
00113 loops++;
00114 }
00115
00116 timeLapse = ( getCurrentTick() + millisecondsPerUpdate - nextTick ) / millisecondsPerUpdate;
00117 drawAll( timeLapse );
00118 }
00119 stopAll();
00120
00121 cleanupAll();
00122 }
00123
00124 void
00125 Game::runGameFixedTimestep( int framesPerSecond )
00126 {
00127 DEBUG_FUNC_NAME
00128
00129 if( !d->currentScene )
00130 {
00131 DEBUG_TEXT( QString( "There is no scene to run!" ) );
00132 return;
00133 }
00134
00135 int millisecondsPerUpdate = 1000 / framesPerSecond;
00136 DEBUG_TEXT( QString( "Running the game using fixed timestep at %1 frames per second (meaning %2 milliseconds between each update and draw)" ).arg( framesPerSecond ).arg( millisecondsPerUpdate ) );
00137
00138 int remainingSleep = 0;
00139 int nextTick = 0;
00140 d->time.start();
00141
00142 d->gameRunning = true;
00143
00144 initializeAll();
00145
00146 startAll();
00147 while( d->gameRunning )
00148 {
00149
00150 QCoreApplication::processEvents();
00151
00152
00153 if( !d->gamePaused )
00154 {
00155 updateAll( millisecondsPerUpdate );
00156 }
00157
00158 drawAll();
00159
00160 nextTick += millisecondsPerUpdate;
00161 remainingSleep = nextTick - this->getCurrentTick();
00162 if( remainingSleep > 0 )
00163 {
00164 DEBUG_TEXT( QString( "Sleeping for %1 milliseconds" ).arg( remainingSleep ) )
00165 I::msleep( remainingSleep );
00166 }
00167 else
00168 {
00169
00170 DEBUG_TEXT( tr( "Gameloop has fallen behind by %1 milliseconds" ).arg( remainingSleep ) )
00171 }
00172 }
00173 stopAll();
00174
00175 cleanupAll();
00176 }
00177
00178 void Game::stopGame()
00179 {
00180 DEBUG_BLOCK
00181 DEBUG_TEXT( QString( "Stopping gameloop" ) )
00182
00183 d->gameRunning = false;
00184 }
00185
00186 void Game::setPause( bool pause )
00187 {
00188 DEBUG_BLOCK
00189 if( pause )
00190 {
00191 DEBUG_TEXT( QString( "Pausing gameloop" ) )
00192 }
00193 else
00194 {
00195 DEBUG_TEXT( QString( "Un-pausing gameloop" ) )
00196 }
00197
00198 d->gamePaused = pause;
00199 }
00200
00201 void Game::initializeAll()
00202 {
00203 d->currentScene->sceneContents()->initialize();
00204 }
00205
00206 void Game::startAll()
00207 {
00208 d->currentScene->sceneContents()->start();
00209 }
00210
00211 void Game::drawAll( int time )
00212 {
00213 d->currentScene->sceneContents()->draw( time );
00214 emit painted( time );
00215 }
00216
00217 void Game::updateAll( int time )
00218 {
00219 d->currentScene->sceneContents()->update( time );
00220 emit updated( time );
00221 }
00222
00223 void Game::stopAll()
00224 {
00225 d->currentScene->sceneContents()->stop();
00226 }
00227
00228 void Game::cleanupAll()
00229 {
00230 d->currentScene->sceneContents()->cleanup();
00231 }
00232
00233 float Game::random()
00234 {
00235 return rand() / float( RAND_MAX );
00236 }
00237
00238
00239
00240
00241
00242 Scene *
00243 Game::currentScene() const
00244 {
00245 return d->currentScene;
00246 }
00247
00248 bool Game::isRunning() const
00249 {
00250 return d->gameRunning;
00251 }
00252
00253 bool Game::isPaused() const
00254 {
00255 return d->gamePaused;
00256 }
00257
00258 void
00259 Game::setCurrentScene( Scene* newCurrentScene )
00260 {
00261 if( d->currentScene )
00262 {
00263 stopAll();
00264 cleanupAll();
00265 }
00266
00267 QList<const GluonCore::GluonObject*> objects = d->listAllChildren( d->currentScene );
00268 foreach( const GluonCore::GluonObject * child, objects )
00269 {
00270 disconnect( child, SIGNAL( showDebug( const QString& ) ), this, SIGNAL( showDebug( const QString& ) ) );
00271 }
00272
00273 d->currentScene = newCurrentScene;
00274
00275 if( d->gameRunning )
00276 {
00277 initializeAll();
00278 startAll();
00279 }
00280
00281 objects = d->listAllChildren( newCurrentScene->sceneContents() );
00282 foreach( const GluonCore::GluonObject * child, objects )
00283 {
00284 connect( child, SIGNAL( showDebug( const QString& ) ), this, SIGNAL( showDebug( const QString& ) ) );
00285 }
00286
00287 emit currentSceneChanged( newCurrentScene );
00288 }
00289
00290 void Game::setCurrentScene( const QString& sceneName )
00291 {
00292 Scene* scene = qobject_cast< GluonEngine::Scene* >( gameProject()->findItemByName( sceneName ) );
00293 if( scene )
00294 setCurrentScene( scene );
00295 }
00296
00297 void Game::resetCurrentScene()
00298 {
00299 if( d->currentScene )
00300 {
00301 if( d->gameRunning )
00302 {
00303 d->resetScene = true;
00304 }
00305 else
00306 {
00307 d->currentScene->resetScene();
00308 }
00309 }
00310 }
00311
00312 GluonEngine::GameProject *
00313 Game::gameProject() const
00314 {
00315 return d->gameProject;
00316 }
00317 void
00318 Game::setGameProject( GluonEngine::GameProject* newGameProject )
00319 {
00320 DEBUG_FUNC_NAME
00321 if( d->gameProject )
00322 {
00323 if( d->currentScene )
00324 {
00325 stopAll();
00326 cleanupAll();
00327 }
00328 delete d->gameProject;
00329 }
00330
00331 d->gameProject = newGameProject;
00332
00333 if( !d->gameProject->entryPoint() )
00334 {
00335 DEBUG_TEXT( QString( "Entry point invalid, attempting to salvage" ) )
00336 Scene* scene = GamePrivate::findSceneInChildren( d->gameProject );
00337 if( scene )
00338 {
00339 d->gameProject->setEntryPoint( scene );
00340 DEBUG_TEXT( QString( "Entry point salvaged by resetting to first Scene in project - %1" ).arg( scene->fullyQualifiedName() ) )
00341 }
00342 }
00343
00344 if( d->gameProject->entryPoint() )
00345 {
00346 DEBUG_TEXT( QString( "Set the gameproject to %1 with the entry point %2" ).arg( d->gameProject->name() ).arg( d->gameProject->entryPoint()->name() ) )
00347 }
00348 else
00349 {
00350 DEBUG_TEXT( QString( "Somehow we have got here with no entrypoint... This is very, very wrong!" ) )
00351 }
00352
00353 d->currentScene = d->gameProject->entryPoint();
00354 emit currentProjectChanged( d->gameProject );
00355 emit currentSceneChanged( d->currentScene );
00356 }
00357
00358 GameObject* Game::getFromScene( const QString& name )
00359 {
00360 return d->currentScene->sceneContents()->childGameObject( name );
00361 }
00362
00363 GameObject* Game::clone( GameObject* obj )
00364 {
00365 if( obj )
00366 {
00367 GameObject* objClone = qobject_cast<GameObject*>( obj->clone() );
00368 QList<const GluonCore::GluonObject*> objects = d->listAllChildren( objClone );
00369 foreach( const GluonCore::GluonObject * child, objects )
00370 {
00371 connect( child, SIGNAL( showDebug( const QString& ) ), this, SIGNAL( showDebug( const QString& ) ) );
00372 }
00373 return objClone;
00374 }
00375
00376 return 0;
00377 }
00378
00379 #include "game.moc"