Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

network: working on campaing and gameworld structure

File size: 17.8 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::load()
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 *  destroys the GameWorld
410*/
411ErrorMessage GameWorld::destroy()
412{
413
414}
415
416/**
417 *  shows the loading screen
418*/
419void GameWorld::displayLoadScreen ()
420{
421  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
422
423  //GLMenuImageScreen*
424  this->glmis = new GLMenuImageScreen();
425  this->glmis->setMaximum(8);
426
427  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
428}
429
430/**
431 * @brief removes the loadscreen, and changes over to the game
432 *
433 * @todo take out the delay
434*/
435void GameWorld::releaseLoadScreen ()
436{
437  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
438  this->glmis->setValue(this->glmis->getMaximum());
439  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
440  delete this->glmis;
441}
442
443
444/**
445 *  synchronize local data with remote data
446*/
447void GameWorld::synchronize ()
448{
449  // Get remote input
450  // Update synchronizables
451/*  NetworkManager::getInstance()->synchronize();*/
452}
453
454
455/**
456 *  run all input processing
457
458   the command node is the central input event dispatcher. the node uses the even-queue from
459   sdl and has its own event-passing-queue.
460*/
461void GameWorld::handleInput ()
462{
463  EventHandler::getInstance()->process();
464
465  // remoteinput
466}
467
468void GameWorld::tick(std::list<WorldEntity*> entityList, float dt)
469{
470  std::list<WorldEntity*>::iterator entity;
471  for (entity = entityList.begin(); entity != entityList.end(); entity++)
472    (*entity)->tick(dt);
473
474}
475
476/**
477 *  advance the timeline
478
479   this calculates the time used to process one frame (with all input handling, drawing, etc)
480   the time is mesured in ms and passed to all world-entities and other classes that need
481   a heart-beat.
482*/
483void GameWorld::tick ()
484{
485  Uint32 currentFrame = SDL_GetTicks();
486  if(!this->bPause)
487    {
488      this->dt = currentFrame - this->lastFrame;
489
490      if( this->dt > 10)
491        {
492          float fps = 1000/dt;
493
494          // temporary, only for showing how fast the text-engine is
495          char tmpChar[20];
496          sprintf(tmpChar, "fps: %4.0f", fps);
497        }
498      else
499        {
500          /* the frame-rate is limited to 100 frames per second, all other things are for
501             nothing.
502          */
503          PRINTF(3)("fps = 1000 - frame rate is adjusted\n");
504          SDL_Delay(10-dt);
505          this->dt = 10;
506        }
507
508      this->dtS = (float)this->dt / 1000.0 * this->speed;
509      this->gameTime += this->dtS;
510
511      this->tick(this->objectManager.getObjectList(OM_DEAD_TICK), this->dtS);
512      this->tick(this->objectManager.getObjectList(OM_COMMON), this->dtS);
513      this->tick(this->objectManager.getObjectList(OM_GROUP_00), this->dtS);
514      this->tick(this->objectManager.getObjectList(OM_GROUP_01), this->dtS);
515      this->tick(this->objectManager.getObjectList(OM_GROUP_01_PROJ), this->dtS);
516
517      /* update tick the rest */
518      this->localCamera->tick(this->dtS);
519      // tick the engines
520      AnimationPlayer::getInstance()->tick(this->dtS);
521//      if (this->cycle > 5)
522        PhysicsEngine::getInstance()->tick(this->dtS);
523
524      ParticleEngine::getInstance()->tick(this->dtS);
525
526
527      /** actualy the Graphics Engine should tick the world not the other way around...
528         but since we like the things not too complicated we got it this way around
529         until there is need or time to do it the other way around.
530         @todo: GraphicsEngine ticks world: separation of processes and data...
531
532        bensch: in my opinion the GraphicsEngine could draw the world, but not tick it,
533         beceause graphics have nothing(or at least not much) to do with Motion.
534      */
535      GraphicsEngine::getInstance()->tick(this->dtS);
536    }
537  this->lastFrame = currentFrame;
538}
539
540
541/**
542 *  this function gives the world a consistant state
543
544   after ticking (updating the world state) this will give a constistant
545   state to the whole system.
546*/
547void GameWorld::update()
548{
549  GraphicsEngine::getInstance()->update(this->dtS);
550  PNode::getNullParent()->updateNode (this->dtS);
551  SoundEngine::getInstance()->update();
552  //music->update();
553}
554
555
556void GameWorld::collide()
557{
558  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_00),
559                                            this->objectManager.getObjectList(OM_GROUP_01_PROJ));
560  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_01),
561                                            this->objectManager.getObjectList(OM_COMMON));
562}
563
564/**
565 *  render the current frame
566
567   clear all buffers and draw the world
568*/
569void GameWorld::display ()
570{
571  // clear buffer
572  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
573  // set camera
574  this->localCamera->apply ();
575  // draw world
576  this->draw();
577  // draw HUD
578  /** @todo draw HUD */
579  // flip buffers
580  GraphicsEngine::swapBuffers();
581  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
582  //SDL_Flip (screen);
583}
584
585
586/**
587 *  runs through all entities calling their draw() methods
588 */
589void GameWorld::draw ()
590{
591  GraphicsEngine* engine = GraphicsEngine::getInstance();
592  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
593  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON));
594  engine->draw(State::getObjectManager()->getObjectList(OM_COMMON));
595  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_00));
596  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01));
597  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
598
599   if( unlikely( this->showBV))  // to draw the bounding boxes of the objects at level 2 for debug purp
600   {
601     CDEngine* engine = CDEngine::getInstance();
602     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
603     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON));
604     engine->drawBV(State::getObjectManager()->getObjectList(OM_COMMON));
605     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_00));
606     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01));
607     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
608   }
609
610//   {
611//     if( entity->isVisible() ) entity->draw();
612  //FIXME
613//     entity = iterator->nextElement();
614//   }
615
616  ParticleEngine::getInstance()->draw();
617
618  if (unlikely(this->showPNodes))
619    PNode::getNullParent()->debugDraw(0);
620
621  engine->draw();
622  //TextEngine::getInstance()->draw();
623}
624
625
626/**
627 * \brief main loop of the world: executing all world relevant function
628 *
629 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
630 * all other member-entities of the world (tick to player, enemies etc.), checking for
631 * collisions drawing everything to the screen.
632 */
633void GameWorld::mainLoop()
634{
635  this->lastFrame = SDL_GetTicks ();
636  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
637
638  while(!this->bQuitWorld) /* @todo implement pause */
639  {
640    ++this->cycle;
641      // Network
642    this->synchronize ();
643      // Process input
644    this->handleInput ();
645    if( this->bQuitWorld)
646      break;
647      // Process time
648    this->tick ();
649      // Process collision
650    this->collide ();
651      // Update the state
652    this->update ();
653      // Draw
654    this->display ();
655  }
656
657  PRINTF(3)("GameWorld::mainLoop() - Exiting the main loop\n");
658}
659
660
661
662/**
663 *  add and spawn a new entity to this world
664 * @param entity to be added
665*/
666void GameWorld::spawn(WorldEntity* entity)
667{
668//   this->entities->add (entity);
669  entity->postSpawn ();
670}
671
672/**
673 *  sets the track path of this world
674 * @param name the name of the path
675 */
676void GameWorld::setPath( const char* name)
677{
678  if (this->path)
679    delete this->path;
680  if (ResourceManager::isFile(name))
681  {
682    this->path = new char[strlen(name)+1];
683    strcpy(this->path, name);
684  }
685  else
686    {
687      this->path = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(name) +1];
688      sprintf(this->path, "%s%s", ResourceManager::getInstance()->getDataDir(), name);
689    }
690}
691
Note: See TracBrowser for help on using the repository browser.