Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/story_entities/game_world.cc @ 6372

Last change on this file since 6372 was 6372, checked in by patrick, 18 years ago

network: more cleanup in the StoryEntity, thightening the interface and function renames

File size: 17.7 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13   co-programmer: Christian Meyer
14   co-programmer: Benjamin Grauer
15*/
16
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
18
19#include "game_world.h"
20
21#include "shell_command.h"
22#include "resource_manager.h"
23#include "state.h"
24
25#include "p_node.h"
26#include "world_entity.h"
27#include "player.h"
28#include "camera.h"
29#include "environment.h"
30#include "terrain.h"
31
32#include "test_entity.h"
33#include "terrain.h"
34#include "light.h"
35#include "load_param.h"
36#include "shell.h"
37
38#include "fast_factory.h"
39#include "animation_player.h"
40#include "particle_engine.h"
41#include "graphics_engine.h"
42#include "physics_engine.h"
43#include "fields.h"
44
45#include "md2Model.h"
46
47#include "glmenu_imagescreen.h"
48#include "game_loader.h"
49
50#include "animation3d.h"
51
52#include "substring.h"
53
54#include "factory.h"
55
56#include "weapons/projectile.h"
57#include "event_handler.h"
58#include "sound_engine.h"
59#include "ogg_player.h"
60
61#include "class_list.h"
62
63#include "cd_engine.h"
64#include "npcs/npc_test1.h"
65#include "shader.h"
66
67#include "playable.h"
68#include "network_manager.h"
69#include "playable.h"
70
71
72SHELL_COMMAND(speed, GameWorld, setSpeed);
73SHELL_COMMAND(togglePNodeVisibility, GameWorld, togglePNodeVisibility);
74SHELL_COMMAND(toggleBVVisibility, GameWorld, toggleBVVisibility);
75
76using namespace std;
77
78//! This creates a Factory to fabricate a GameWorld
79CREATE_FACTORY(GameWorld, CL_GAME_WORLD);
80
81
82
83GameWorld::GameWorld(const TiXmlElement* root)
84{
85  this->setClassID(CL_GAME_WORLD, "GameWorld");
86  this->setName("Preloaded World - no name yet");
87
88  this->gameTime = 0.0f;
89  this->setSpeed(1.0f);
90  this->music = NULL;
91  this->shell = NULL;
92  this->localPlayer = NULL;
93  this->localCamera = NULL;
94
95  this->showPNodes = false;
96  this->showBV = false;
97
98  this->path = NULL;
99
100  this->loadParams(root);
101}
102
103/**
104 *  remove the GameWorld from memory
105 *
106 *  delete everything explicitly, that isn't contained in the parenting tree!
107 *  things contained in the tree are deleted automaticaly
108 */
109GameWorld::~GameWorld ()
110{
111  delete this->shell;
112  PRINTF(3)("GameWorld::~GameWorld() - deleting current world\n");
113
114  delete this->localPlayer;
115
116  // delete all the initialized Engines.
117  FastFactory::flushAll(true);
118  delete LightManager::getInstance();
119  delete ParticleEngine::getInstance();
120  delete AnimationPlayer::getInstance();
121  delete PhysicsEngine::getInstance();
122
123  // external engines initialized by the orxonox-class get deleted
124  SoundEngine::getInstance()->flushAllBuffers();
125  SoundEngine::getInstance()->flushAllSources();
126
127  if (State::getObjectManager() == &this->objectManager)
128    State::setObjectManager(NULL);
129  // erease everything that is left.
130  delete PNode::getNullParent();
131
132  //secondary cleanup of PNodes;
133  const std::list<BaseObject*>* nodeList = ClassList::getList(CL_PARENT_NODE);
134  if (nodeList != NULL)
135    while (!nodeList->empty())
136      delete nodeList->front();
137
138  Shader::suspendShader();
139
140  // unload the resources !!
141  ResourceManager::getInstance()->unloadAllByPriority(RP_LEVEL);
142}
143
144
145
146/**
147 * loads the parameters of a GameWorld from an XML-element
148 * @param root the XML-element to load from
149 */
150void GameWorld::loadParams(const TiXmlElement* root)
151{
152  PRINTF(4)("Creating a GameWorld\n");
153
154  LoadParam(root, "identifier", this, GameWorld, setStoryID)
155    .describe("Sets the StoryID of this world");
156
157  LoadParam(root, "nextid", this, GameWorld, setNextStoryID)
158    .describe("Sets the ID of the next world");
159
160  LoadParam(root, "path", this, GameWorld, setPath)
161    .describe("The Filename of this GameWorld (relative from the data-dir)");
162}
163
164
165/**
166 * this is executed just before load
167 *
168 * since the load function sometimes needs data, that has been initialized
169 * before the load and after the proceeding storyentity has finished
170*/
171ErrorMessage GameWorld::init()
172{
173  State::setObjectManager(&this->objectManager);
174  this->cycle = 0;
175
176  /* init the world interface */
177  this->shell = new Shell();
178
179  LightManager::getInstance();
180  PNode::getNullParent();
181
182  AnimationPlayer::getInstance(); // initializes the animationPlayer
183  ParticleEngine::getInstance();
184  PhysicsEngine::getInstance();
185
186  this->localCamera = new Camera();
187  this->localCamera->setName ("GameWorld-Camera");
188
189  State::setCamera(this->localCamera, this->localCamera->getTarget());
190
191  GraphicsEngine::getInstance()->displayFPS(true);
192}
193
194
195/**
196 *  loads the GameWorld by initializing all resources, and set their default values.
197 */
198ErrorMessage GameWorld::loadData()
199{
200  this->displayLoadScreen();
201
202  PRINTF(3)("> Loading world: '%s'\n", getPath());
203  TiXmlElement* element;
204  GameLoader* loader = GameLoader::getInstance();
205
206  if( getPath() == NULL)
207    {
208      PRINTF(1)("GameWorld has no path specified for loading");
209      return (ErrorMessage){213,"Path not specified","GameWorld::load()"};
210    }
211
212  TiXmlDocument* XMLDoc = new TiXmlDocument( getPath());
213  // load the campaign document
214  if( !XMLDoc->LoadFile())
215  {
216    // report an error
217    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getPath(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
218    delete XMLDoc;
219    return (ErrorMessage){213,"XML File parsing error","GameWorld::load()"};
220  }
221
222  // check basic validity
223  TiXmlElement* root = XMLDoc->RootElement();
224  assert( root != NULL);
225
226  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
227    {
228      // report an error
229      PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
230      delete XMLDoc;
231      return (ErrorMessage){213,"Path not a WorldDataFile","GameWorld::load()"};
232    }
233
234  // load the parameters
235  // name
236  const char* string = grabParameter( root, "name");
237  if( string == NULL)
238    {
239      PRINTF(2)("GameWorld is missing a proper 'name'\n");
240      this->setName("Unknown");
241    }
242  else
243    {
244      this->setName(string);
245    }
246
247  ////////////////
248  // LOADSCREEN //
249  ////////////////
250  element = root->FirstChildElement("LoadScreen");
251  if (element == NULL)
252    {
253      PRINTF(2)("no LoadScreen specified, loading default\n");
254
255      glmis->setBackgroundImage("pictures/load_screen.jpg");
256      this->glmis->setMaximum(8);
257      this->glmis->draw();
258    }
259  else
260    {
261      this->glmis->loadParams(element);
262      this->glmis->draw();
263    }
264  this->glmis->draw();
265
266  ////////////////////////
267  // find WorldEntities //
268  ////////////////////////
269
270  element = root->FirstChildElement("WorldEntities");
271
272  if( element == NULL)
273    {
274      PRINTF(1)("GameWorld is missing 'WorldEntities'\n");
275    }
276  else
277    {
278      element = element->FirstChildElement();
279      // load Players/Objects/Whatever
280      PRINTF(4)("Loading WorldEntities\n");
281      while( element != NULL)
282        {
283          BaseObject* created = Factory::fabricate(element);
284          if( created != NULL )
285          {
286            if(created->isA(CL_WORLD_ENTITY))
287              this->spawn(dynamic_cast<WorldEntity*>(created));
288            printf("Created a %s: %s\n", created->getClassName(), created->getName());
289          }
290
291          // if we load a 'Player' we use it as localPlayer
292
293
294          //todo do this more elegant
295          if( element->Value() != NULL && !strcmp( element->Value(), "SkyBox"))
296            this->sky = dynamic_cast<WorldEntity*>(created);
297          if( element->Value() != NULL && !strcmp( element->Value(), "Terrain"))
298          {
299            terrain = dynamic_cast<Terrain*>(created);
300            CDEngine::getInstance()->setTerrain(terrain);
301          }
302          element = element->NextSiblingElement();
303          glmis->step(); //! @todo temporary
304        }
305      PRINTF(4)("Done loading WorldEntities\n");
306    }
307
308    //////////////////////////////
309    // LOADING ADDITIONAL STUFF //
310    //////////////////////////////
311
312    LoadParamXML(root, "LightManager", LightManager::getInstance(), LightManager, loadParams);
313
314   LoadParamXML(root, "ParticleEngine", ParticleEngine::getInstance(), ParticleEngine, loadParams);
315//   LoadParamXML(root, "PhysicsEngine", PhysicsEngine::getInstance(), PhysicsEngine, loadParams);
316
317  // free the XML data
318
319  delete XMLDoc;
320  /* GENERIC LOADING PROCESS FINISHED */
321
322
323  // Create a Player
324  this->localPlayer = new Player();
325
326  Playable* playable;
327  const list<BaseObject*>* playableList = ClassList::getList(CL_PLAYABLE);
328  if (playableList != NULL)
329  {
330    playable = dynamic_cast<Playable*>(playableList->front());
331    this->localPlayer->setControllable(playable);
332  }
333
334
335//   //localCamera->setParent(TrackNode::getInstance());
336//  tn->addChild(this->localCamera);
337  localCamera->setClipRegion(1, 10000.0);
338//  localCamera->lookAt(playable);
339//  this->localPlayer->setParentMode(PNODE_ALL);
340  if (this->sky != NULL)
341  {
342    this->localCamera->addChild(sky);
343  }
344  SoundEngine::getInstance()->setListener(this->localCamera);
345
346  /* some static stuff*/
347
348  this->music = NULL;
349  //(OggPlayer*)ResourceManager::getInstance()->load("sound/00-luke_grey_-_hypermode.ogg", OGG, RP_LEVEL);
350  //music->playback();
351
352  this->releaseLoadScreen();
353}
354
355
356/**
357 *  initializes a new GameWorld shortly before start
358 *
359 * this is the function, that will be loaded shortly before the world is
360 * started
361*/
362ErrorMessage GameWorld::preStart()
363{
364  this->bPause = false;
365
366  /* update the object position before game start - so there are no wrong coordinates used in the first processing */
367  PNode::getNullParent()->updateNode (0.001f);
368  PNode::getNullParent()->updateNode (0.001f);
369}
370
371
372/**
373 *  starts the GameWorld
374 */
375ErrorMessage GameWorld::start()
376{
377  this->bQuitWorld = false;
378  this->mainLoop();
379}
380
381/**
382 *  stops the world.
383
384   This happens, when the player decides to end the Level.
385*/
386ErrorMessage GameWorld::stop()
387{
388  PRINTF(3)("GameWorld::stop() - got stop signal\n");
389  this->bQuitWorld= true;
390}
391
392/**
393 *  pauses the Game
394*/
395ErrorMessage GameWorld::pause()
396{
397  this->isPaused = true;
398}
399
400/**
401 *  ends the pause Phase
402*/
403ErrorMessage GameWorld::resume()
404{
405  this->isPaused = false;
406}
407
408
409/**
410 *  shows the loading screen
411*/
412void GameWorld::displayLoadScreen ()
413{
414  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
415
416  //GLMenuImageScreen*
417  this->glmis = new GLMenuImageScreen();
418  this->glmis->setMaximum(8);
419
420  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
421}
422
423/**
424 * @brief removes the loadscreen, and changes over to the game
425 *
426 * @todo take out the delay
427*/
428void GameWorld::releaseLoadScreen ()
429{
430  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
431  this->glmis->setValue(this->glmis->getMaximum());
432  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
433  delete this->glmis;
434}
435
436
437/**
438 *  synchronize local data with remote data
439*/
440void GameWorld::synchronize ()
441{
442  // Get remote input
443  // Update synchronizables
444/*  NetworkManager::getInstance()->synchronize();*/
445}
446
447
448/**
449 *  run all input processing
450
451   the command node is the central input event dispatcher. the node uses the even-queue from
452   sdl and has its own event-passing-queue.
453*/
454void GameWorld::handleInput ()
455{
456  EventHandler::getInstance()->process();
457
458  // remoteinput
459}
460
461void GameWorld::tick(std::list<WorldEntity*> entityList, float dt)
462{
463  std::list<WorldEntity*>::iterator entity;
464  for (entity = entityList.begin(); entity != entityList.end(); entity++)
465    (*entity)->tick(dt);
466
467}
468
469/**
470 *  advance the timeline
471
472   this calculates the time used to process one frame (with all input handling, drawing, etc)
473   the time is mesured in ms and passed to all world-entities and other classes that need
474   a heart-beat.
475*/
476void GameWorld::tick ()
477{
478  Uint32 currentFrame = SDL_GetTicks();
479  if(!this->bPause)
480    {
481      this->dt = currentFrame - this->lastFrame;
482
483      if( this->dt > 10)
484        {
485          float fps = 1000/dt;
486
487          // temporary, only for showing how fast the text-engine is
488          char tmpChar[20];
489          sprintf(tmpChar, "fps: %4.0f", fps);
490        }
491      else
492        {
493          /* the frame-rate is limited to 100 frames per second, all other things are for
494             nothing.
495          */
496          PRINTF(3)("fps = 1000 - frame rate is adjusted\n");
497          SDL_Delay(10-dt);
498          this->dt = 10;
499        }
500
501      this->dtS = (float)this->dt / 1000.0 * this->speed;
502      this->gameTime += this->dtS;
503
504      this->tick(this->objectManager.getObjectList(OM_DEAD_TICK), this->dtS);
505      this->tick(this->objectManager.getObjectList(OM_COMMON), this->dtS);
506      this->tick(this->objectManager.getObjectList(OM_GROUP_00), this->dtS);
507      this->tick(this->objectManager.getObjectList(OM_GROUP_01), this->dtS);
508      this->tick(this->objectManager.getObjectList(OM_GROUP_01_PROJ), this->dtS);
509
510      /* update tick the rest */
511      this->localCamera->tick(this->dtS);
512      // tick the engines
513      AnimationPlayer::getInstance()->tick(this->dtS);
514//      if (this->cycle > 5)
515        PhysicsEngine::getInstance()->tick(this->dtS);
516
517      ParticleEngine::getInstance()->tick(this->dtS);
518
519
520      /** actualy the Graphics Engine should tick the world not the other way around...
521         but since we like the things not too complicated we got it this way around
522         until there is need or time to do it the other way around.
523         @todo: GraphicsEngine ticks world: separation of processes and data...
524
525        bensch: in my opinion the GraphicsEngine could draw the world, but not tick it,
526         beceause graphics have nothing(or at least not much) to do with Motion.
527      */
528      GraphicsEngine::getInstance()->tick(this->dtS);
529    }
530  this->lastFrame = currentFrame;
531}
532
533
534/**
535 *  this function gives the world a consistant state
536
537   after ticking (updating the world state) this will give a constistant
538   state to the whole system.
539*/
540void GameWorld::update()
541{
542  GraphicsEngine::getInstance()->update(this->dtS);
543  PNode::getNullParent()->updateNode (this->dtS);
544  SoundEngine::getInstance()->update();
545  //music->update();
546}
547
548
549void GameWorld::collide()
550{
551  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_00),
552                                            this->objectManager.getObjectList(OM_GROUP_01_PROJ));
553  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_01),
554                                            this->objectManager.getObjectList(OM_COMMON));
555}
556
557/**
558 *  render the current frame
559
560   clear all buffers and draw the world
561*/
562void GameWorld::display ()
563{
564  // clear buffer
565  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
566  // set camera
567  this->localCamera->apply ();
568  // draw world
569  this->draw();
570  // draw HUD
571  /** @todo draw HUD */
572  // flip buffers
573  GraphicsEngine::swapBuffers();
574  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
575  //SDL_Flip (screen);
576}
577
578
579/**
580 *  runs through all entities calling their draw() methods
581 */
582void GameWorld::draw ()
583{
584  GraphicsEngine* engine = GraphicsEngine::getInstance();
585  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
586  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON));
587  engine->draw(State::getObjectManager()->getObjectList(OM_COMMON));
588  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_00));
589  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01));
590  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
591
592   if( unlikely( this->showBV))  // to draw the bounding boxes of the objects at level 2 for debug purp
593   {
594     CDEngine* engine = CDEngine::getInstance();
595     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
596     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON));
597     engine->drawBV(State::getObjectManager()->getObjectList(OM_COMMON));
598     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_00));
599     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01));
600     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
601   }
602
603//   {
604//     if( entity->isVisible() ) entity->draw();
605  //FIXME
606//     entity = iterator->nextElement();
607//   }
608
609  ParticleEngine::getInstance()->draw();
610
611  if (unlikely(this->showPNodes))
612    PNode::getNullParent()->debugDraw(0);
613
614  engine->draw();
615  //TextEngine::getInstance()->draw();
616}
617
618
619/**
620 * \brief main loop of the world: executing all world relevant function
621 *
622 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
623 * all other member-entities of the world (tick to player, enemies etc.), checking for
624 * collisions drawing everything to the screen.
625 */
626void GameWorld::mainLoop()
627{
628  this->lastFrame = SDL_GetTicks ();
629  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
630
631  while(!this->bQuitWorld) /* @todo implement pause */
632  {
633    ++this->cycle;
634      // Network
635    this->synchronize ();
636      // Process input
637    this->handleInput ();
638    if( this->bQuitWorld)
639      break;
640      // Process time
641    this->tick ();
642      // Process collision
643    this->collide ();
644      // Update the state
645    this->update ();
646      // Draw
647    this->display ();
648  }
649
650  PRINTF(3)("GameWorld::mainLoop() - Exiting the main loop\n");
651}
652
653
654
655/**
656 *  add and spawn a new entity to this world
657 * @param entity to be added
658*/
659void GameWorld::spawn(WorldEntity* entity)
660{
661//   this->entities->add (entity);
662  entity->postSpawn ();
663}
664
665/**
666 *  sets the track path of this world
667 * @param name the name of the path
668 */
669void GameWorld::setPath( const char* name)
670{
671  if (this->path)
672    delete this->path;
673  if (ResourceManager::isFile(name))
674  {
675    this->path = new char[strlen(name)+1];
676    strcpy(this->path, name);
677  }
678  else
679    {
680      this->path = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(name) +1];
681      sprintf(this->path, "%s%s", ResourceManager::getInstance()->getDataDir(), name);
682    }
683}
684
Note: See TracBrowser for help on using the repository browser.