Changeset 2844 for code/branches/gui/src/core/Game.cc
- Timestamp:
- Mar 25, 2009, 5:23:00 PM (15 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
code/branches/gui/src/core/Game.cc
r2843 r2844 33 33 */ 34 34 35 #include "OrxonoxStableHeaders.h"36 35 #include "Game.h" 37 36 … … 41 40 #include "util/Debug.h" 42 41 #include "util/Exception.h" 43 #include "core/CommandLine.h" 44 #include "core/ConsoleCommand.h" 45 #include "core/Core.h" 46 #include "core/Identifier.h" 47 #include "core/CoreIncludes.h" 48 #include "core/ConfigValueIncludes.h" 49 50 #include "gamestates/GSRoot.h" 51 #include "gamestates/GSGraphics.h" 52 #include "gamestates/GSStandalone.h" 53 #include "gamestates/GSServer.h" 54 #include "gamestates/GSClient.h" 55 #include "gamestates/GSDedicated.h" 56 #include "gamestates/GSGUI.h" 57 #include "gamestates/GSIOConsole.h" 58 59 /* 60 @brief 61 Main method. Game starts here (except for static initialisations). 62 */ 63 int main(int argc, char** argv) 64 { 65 { 66 orxonox::Game orxonox(argc, argv); 67 orxonox.run(); 68 // objects gets destroyed here! 69 } 70 71 // Clean up class hierarchy stuff (identifiers, xmlport, configvalue, consolecommand) 72 // Needs to be done after Game destructor because of ~OrxonoxClass 73 orxonox::Identifier::destroyAllIdentifiers(); 74 75 return 0; 76 } 42 #include "Clock.h" 43 #include "CommandLine.h" 44 #include "ConsoleCommand.h" 45 #include "Core.h" 46 #include "CoreIncludes.h" 47 #include "ConfigValueIncludes.h" 48 #include "GameState.h" 77 49 78 50 namespace orxonox … … 83 55 } 84 56 57 struct _CoreExport GameStateTreeNode 58 { 59 GameState* state_; 60 GameStateTreeNode* parent_; 61 std::vector<GameStateTreeNode*> children_; 62 }; 63 85 64 SetCommandLineArgument(state, "gui").shortcut("s"); 65 SetCommandLineSwitch(startWithConsole); 86 66 SetConsoleCommandShortcutExternAlias(stop_game, "exit"); 87 67 68 std::map<std::string, GameState*> Game::allStates_s; 88 69 Game* Game::singletonRef_s = 0; 89 70 … … 96 77 assert(singletonRef_s == 0); 97 78 singletonRef_s = this; 79 80 this->rootStateNode_ = 0; 81 this->activeStateNode_ = 0; 98 82 99 83 this->abort_ = false; … … 121 105 // Destroy pretty much everyhting left 122 106 delete this->core_; 107 108 // Delete all GameStates created by the macros 109 for (std::map<std::string, GameState*>::const_iterator it = allStates_s.begin(); it != allStates_s.end(); ++it) 110 delete it->second; 123 111 124 112 assert(singletonRef_s); … … 144 132 void Game::run() 145 133 { 146 // create the gamestates 147 GSRoot root; 148 GSGraphics graphics; 149 GSStandalone standalone; 150 GSServer server; 151 GSClient client; 152 GSDedicated dedicated; 153 GSGUI gui; 154 GSIOConsole ioConsole; 155 156 // make the hierarchy 157 root.addChild(&graphics); 158 graphics.addChild(&standalone); 159 graphics.addChild(&server); 160 graphics.addChild(&client); 161 graphics.addChild(&gui); 162 root.addChild(&ioConsole); 163 root.addChild(&dedicated); 164 165 root.activate(); 166 167 // get initial state from command line 168 root.gotoState(CommandLine::getValue("state")); 134 // </EXPORT THIS> 135 this->setStateHierarchy( 136 "root" 137 " graphics" 138 " gui" 139 " standalone" 140 " level" 141 " server" 142 " level" 143 " client" 144 " level" 145 " dedicated" 146 " level" 147 " ioConsole" 148 ); 149 // </EXPORT THIS> 150 151 152 // Always start with the root state 153 this->requestedStateNodes_.push_back(this->rootStateNode_); 154 this->activeStateNode_ = this->rootStateNode_; 155 this->loadState(this->rootStateNode_->state_); 156 157 // <EXPORT THIS> 158 if (CommandLine::getValue("startWithConsole").getBool()) 159 { 160 // Start the game in the console 161 this->requestState("ioConsole"); 162 } 163 else 164 { 165 // Start in GUI main menu 166 this->requestState("graphics"); 167 this->requestState("gui"); 168 } 169 // </EXPORT THIS> 169 170 170 171 this->gameClock_->capture(); // first delta time should be about 0 seconds 171 while (!this->abort_ )172 while (!this->abort_ && !this->activeStates_.empty()) 172 173 { 173 174 this->gameClock_->capture(); … … 179 180 this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds(); 180 181 181 // UPDATE 182 root.tick(*this->gameClock_); 182 // UPDATE STATE STACK 183 while (this->requestedStateNodes_.size() > 1) 184 { 185 // Note: this->requestedStateNodes_.front() is the currently active state node 186 std::vector<GameStateTreeNode*>::iterator it = this->requestedStateNodes_.begin() + 1; 187 if (*it == this->activeStateNode_->parent_) 188 this->unloadState(this->activeStateNode_->state_); 189 else // has to be child 190 this->loadState((*it)->state_); 191 this->activeStateNode_ = *it; 192 this->requestedStateNodes_.erase(this->requestedStateNodes_.begin()); 193 } 194 195 // UPDATE, bottom to top in the stack 196 for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin(); 197 it != this->activeStates_.end(); ++it) 198 (*it)->update(*this->gameClock_); 183 199 184 200 // STATISTICS … … 206 222 this->periodTime_ -= this->statisticsRefreshCycle_; 207 223 } 208 209 if (root.stateRequest_ != "") 210 root.gotoState(root.stateRequest_);211 }212 213 root.gotoState("root");214 root.deactivate();224 } 225 226 // Unload all remaining states 227 while (!this->activeStates_.empty()) 228 this->unloadState(this->activeStates_.back()); 229 this->activeStateNode_ = 0; 230 this->requestedStateNodes_.clear(); 215 231 } 216 232 … … 226 242 this->periodTickTime_+=length; 227 243 } 244 245 246 /***** GameState related *****/ 247 248 void Game::requestState(const std::string& name) 249 { 250 GameState* state = this->getState(name); 251 if (state == NULL || this->activeStateNode_ == NULL) 252 return; 253 254 GameStateTreeNode* requestedNode = 0; 255 256 // this->requestedStateNodes_.back() is the currently active state 257 GameStateTreeNode* lastRequestedNode = this->requestedStateNodes_.back(); 258 259 // Already the active node? 260 if (state == lastRequestedNode->state_) 261 { 262 COUT(2) << "Warning: Requesting the currently active state! Ignoring." << std::endl; 263 return; 264 } 265 266 // Check children first 267 for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i) 268 { 269 if (lastRequestedNode->children_[i]->state_ == state) 270 { 271 requestedNode = lastRequestedNode->children_[i]; 272 break; 273 } 274 } 275 276 // Check parent and all its grand parents 277 GameStateTreeNode* currentNode = lastRequestedNode; 278 while (requestedNode == NULL && currentNode->parent_ != NULL) 279 { 280 if (currentNode->state_ == state) 281 requestedNode = currentNode; 282 currentNode = currentNode->parent_; 283 } 284 285 if (requestedNode == NULL) 286 COUT(1) << "Error: Requested GameState transition is not allowed. Ignoring." << std::endl; 287 else 288 this->requestedStateNodes_.push_back(requestedNode); 289 } 290 291 void Game::popState() 292 { 293 if (this->activeStateNode_ != NULL && this->requestedStateNodes_.back()->parent_) 294 this->requestState(this->requestedStateNodes_.back()->parent_->state_->getName()); 295 else 296 COUT(2) << "Warning: Could not pop GameState. Ignoring." << std::endl; 297 } 298 299 GameState* Game::getState(const std::string& name) 300 { 301 std::map<std::string, GameState*>::const_iterator it = allStates_s.find(name); 302 if (it != allStates_s.end()) 303 return it->second; 304 else 305 { 306 COUT(1) << "Error: Could not find GameState '" << name << "'. Ignoring." << std::endl; 307 return 0; 308 } 309 } 310 311 void Game::setStateHierarchy(const std::string& str) 312 { 313 // Split string into pieces of the form whitespacesText 314 std::vector<std::pair<std::string, unsigned> > stateStrings; 315 size_t pos = 0; 316 size_t startPos = 0; 317 while (pos < str.size()) 318 { 319 unsigned indentation = 0; 320 while(pos < str.size() && str[pos] == ' ') 321 ++indentation, ++pos; 322 startPos = pos; 323 while(pos < str.size() && str[pos] != ' ') 324 ++pos; 325 stateStrings.push_back(std::pair<std::string, unsigned>( 326 str.substr(startPos, pos - startPos), indentation)); 327 } 328 unsigned int currentLevel = 0; 329 GameStateTreeNode* currentNode = 0; 330 for (std::vector<std::pair<std::string, unsigned> >::const_iterator it = stateStrings.begin(); it != stateStrings.end(); ++it) 331 { 332 std::string newStateName = it->first; 333 unsigned newLevel = it->second; 334 GameState* newState = this->getState(newStateName); 335 if (!newState) 336 ThrowException(GameState, std::string("GameState with name '") + newStateName + "' not found!"); 337 if (newLevel == 0) 338 { 339 // root 340 if (this->rootStateNode_ != NULL) 341 ThrowException(GameState, "No two root GameStates are allowed!"); 342 GameStateTreeNode* newNode = new GameStateTreeNode; 343 newNode->state_ = newState; 344 newNode->parent_ = 0; 345 this->rootStateNode_ = newNode; 346 currentNode = this->rootStateNode_; 347 } 348 else if (currentNode) 349 { 350 GameStateTreeNode* newNode = new GameStateTreeNode; 351 newNode->state_ = newState; 352 if (newLevel < currentLevel) 353 { 354 // Get down the hierarchy 355 do 356 currentNode = currentNode->parent_; 357 while (newLevel < --currentLevel); 358 } 359 if (newLevel == currentLevel) 360 { 361 // same level 362 newNode->parent_ = currentNode->parent_; 363 newNode->parent_->children_.push_back(newNode); 364 } 365 else if (newLevel == currentLevel + 1) 366 { 367 // child 368 newNode->parent_ = currentNode; 369 currentNode->children_.push_back(newNode); 370 } 371 else 372 ThrowException(GameState, "Indentation error while parsing the hierarchy."); 373 currentNode = newNode; 374 currentLevel = newLevel; 375 } 376 else 377 { 378 ThrowException(GameState, "No root GameState specified!"); 379 } 380 } 381 } 382 383 /*** Internal ***/ 384 385 void Game::loadState(GameState* state) 386 { 387 state->activate(); 388 this->activeStates_.push_back(state); 389 } 390 391 void Game::unloadState(orxonox::GameState* state) 392 { 393 state->deactivate(); 394 this->activeStates_.pop_back(); 395 } 396 397 /*static*/ bool Game::addGameState(GameState* state) 398 { 399 std::map<std::string, GameState*>::const_iterator it = allStates_s.find(state->getName()); 400 if (it == allStates_s.end()) 401 allStates_s[state->getName()] = state; 402 else 403 ThrowException(GameState, "Cannot add two GameStates with the same name to 'Game'."); 404 405 // just a required dummy return value 406 return true; 407 } 228 408 }
Note: See TracChangeset
for help on using the changeset viewer.