Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

network: inlined some functions

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