Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

network: many changes in the StoryEntity and Campaign framework: introduced CampaignData as a container for the data of the Campaign and made some changes in the GameWorlds, which are not yet finished

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