Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/main_reto_vs05/src/run_manager.cc @ 161

Last change on this file since 161 was 161, checked in by rgrieder, 16 years ago
  • added namespace Orxonox to every file
    • removed all the "using namespace Ogre" in the header files
  • cleaned up with the includes: attempt to include as little as possible to reduce compile time.
    • created a header file: orxonox_prerequisites.h
    • used OgrePrerequisites in the header files
    • avoided including "Ogre.h", using separate files instead
  • created empty class: AmmunitionDump
File size: 18.6 KB
Line 
1/*
2*   ORXONOX - the hottest 3D action shooter ever to exist
3*
4*
5*   License notice:
6*
7*   This program is free software: you can redistribute it and/or modify
8*   it under the terms of the GNU General Public License as published by
9*   the Free Software Foundation, either version 3 of the License, or
10*   (at your option) any later version.
11*
12*   This program is distributed in the hope that it will be useful,
13*   but WITHOUT ANY WARRANTY; without even the implied warranty of
14*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*   GNU General Public License for more details.
16*
17*   You should have received a copy of the GNU General Public License
18*   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*
20*
21*   Author:
22*      Reto Grieder
23*   Co-authors:
24*      ...
25*/
26
27
28/**
29* RunManager is the basic control object during the game.
30*
31* The RunManger class is designed to actually "run" the main part of the
32* game. The Idea is, that you could derive from the RunManager in order
33* to distinguish between a first person shooter or a space craft shooter.
34* RunManager loads and initialises everything in the scene (like the ship,
35* the enemies in the scene, any scripts, the physics, window events,
36* environment, HUD, etc.).
37* It also captures any input from keyboard, mous, joystick (optional) or
38* Ogre (window events).
39*/
40
41#include "Ogre.h"
42//#include "OgreRoot.h"
43//#include "OgreSceneManager.h"
44//#include "OgreSceneNode.h"
45//#include "OgreCamera.h"
46//#include "OgreViewport.h"
47//#include "OgreRenderWindow.h"
48//#include "OgreOverlay.h"
49//#include "OgreOverlayManager.h"
50//#include "OgreOverlayElement.h"
51//#include "OgreTextureManager.h"
52//#include "OgreMaterialManager.h"
53//#include "OgreLogManager.h"
54//#include "OgreVector3.h"
55//#include "OgreStringConverter.h"
56//#include "OgreWindowEventUtilities.h"
57
58//Use this define to signify OIS will be used as a DLL
59//(so that dll import/export macros are in effect)
60#define OIS_DYNAMIC_LIB
61#include <OIS/OIS.h>
62
63#include "ogre_control.h"
64#include "orxonox_scene.h"
65#include "orxonox_ship.h"
66#include "bullet.h"
67#include "camera_manager.h"
68
69#include "run_manager.h"
70
71namespace Orxonox {
72  using namespace Ogre;
73
74  /**
75  * Contructor only needs the render window and the Root object which are both
76  * the OgreControl object.
77  * Right now the constructor does all the initialisation work. This could also
78  * be done in a new method "initialize()", for whatever purpose.
79  *
80  *
81  * @param ogre_ The OgreControl object holding the render window and the Root
82  */
83  RunManager::RunManager(OgreControl * ogre)
84        : ogre_(ogre), window_(ogre->getRenderWindow()), leftButtonDown_(false),
85        statsOn_(true), screenShotCounter_(0), timeUntilNextToggle_(0),
86        filtering_(TFO_BILINEAR), aniso_(1), sceneDetailIndex_(0),
87        mouseSensitivity_(0.003),
88        debugOverlay_(0), inputManager_(0), mouse_(0), keyboard_(0), joystick_(0)
89  {
90
91    // SETTING UP THE SCENE
92
93    // create one new SceneManger
94    sceneMgr_ = ogre_->getRoot()->createSceneManager(ST_GENERIC, "backgroundScene_");
95
96    // background scene (world objects, skybox, lights, etc.)
97    backgroundScene_ = new OrxonoxScene(sceneMgr_);
98
99    // PLAYER SPACESHIP
100
101    // Create a space ship object and its SceneNode.
102    // Some ideas about the steering: The ship should only receive events like
103    // up, down, left, right, roll left, roll right, move down, move up, etc).
104    // Multiple interpretations of these commands would make the game more
105    // but it also makes AI steering more difficult, since for every type of
106    // steering, new methods have to be written.
107    // --> clearly define how a space ship can fly (rolling?, conservation of
108    // impuls?, direct mouse sight steeering?, etc.)
109    // It should also be considered, that the ship should provide another Node
110    // for a camera to be attached (otherwise the spaceship in front of the
111    // would be very static, never moving at all).
112
113    // Construct a new spaceship and give it the node
114    playerShip_ = new OrxonoxShip(sceneMgr_, sceneMgr_->getRootSceneNode()
115      ->createChildSceneNode("ShipNode", Vector3(20, 20, 20)));
116
117
118    // RESOURCE LOADING (using ResourceGroups if implemented)
119
120    // load all resources and create the entities by calling the initialise()
121    // methods for each object (don't initialise in the constructor!).
122    backgroundScene_->initialise();
123    playerShip_->initialise();
124
125
126    // CAMERA AND VIEWPORT
127    // TODO: create a camera manager. It should be able to change its position
128    // around the space ship (predefined states would be nice too). And it should
129    // also be able to switch between different locations (like ship, spactator,
130    // certain fixed positions (e.g. finish line, etc.)). These are just ideas.
131
132    // create camera and viewport
133    createCamera();
134    createViewports();
135
136
137    // Set default mipmap level (NB some APIs ignore this)
138    TextureManager::getSingleton().setDefaultNumMipmaps(5);
139
140   
141    // BULLET LIST FOR THE TEST APPLICATION
142
143    // TODO: Use STL to make life easier. But it works this way too..
144    bullets_ = new Bullet*[10];
145    bulletsIndex_ = 0;
146    bulletsSize_ = 10;
147
148
149    // HUMAN INTERFACE
150
151    using namespace OIS;
152
153    debugOverlay_ = OverlayManager::getSingleton()
154      .getByName("Core/DebugOverlay");
155
156    LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
157    ParamList pl;
158    size_t windowHnd = 0;
159    std::ostringstream windowHndStr;
160
161    window_->getCustomAttribute("WINDOW", &windowHnd);
162    windowHndStr << windowHnd;
163    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
164
165    inputManager_ = InputManager::createInputSystem( pl );
166
167    // Create all devices (We only catch joystick exceptions here,
168    // as, most people have Key/Mouse)
169    keyboard_ = static_cast<Keyboard*>(inputManager_
170      ->createInputObject( OISKeyboard, false ));
171    mouse_ = static_cast<Mouse*>(inputManager_
172      ->createInputObject( OISMouse, false ));
173    try {
174      joystick_ = static_cast<JoyStick*>(inputManager_
175        ->createInputObject( OISJoyStick, false ));
176    }
177    catch(...) {
178      joystick_ = 0;
179    }
180
181    //Set initial mouse clipping size
182    windowResized(window_);
183
184    showDebugOverlay(true);
185
186    // REGISTER THIS OBJECT AS A WINDOW EVENT LISTENER IN OGRE
187    // It will then receive events liek windowClosed, windowResized, etc.
188    WindowEventUtilities::addWindowEventListener(window_, this);
189  }
190
191  /**
192  * Standard destructor.
193  * Removes this object as a window event listener and deletes all created
194  * variables.
195  */
196  RunManager::~RunManager()
197  {
198    //Remove ourself as a Window listener
199    WindowEventUtilities::removeWindowEventListener(window_, this);
200    windowClosed(window_);
201
202    if (backgroundScene_)
203      delete backgroundScene_;
204    if (playerShip_)
205      delete playerShip_;
206
207    // clean up the bullet list
208    for (int i = 0; i < bulletsIndex_; i++)
209      delete bullets_[i];
210    delete bullets_;
211  }
212
213
214  /**
215  * Method to compute anyting between 2 frames.
216  *
217  * Everything that needs to be computed during the games happens right here.
218  * The only exception are the listeners (which should only set variables,
219  * not actually do something).
220  *
221  * @param time Absolute play time
222  * @param deltaTime Time passed since last frame
223  * @return Return false to end rendering
224  */
225  bool RunManager::tick(unsigned long time, float deltaTime)
226  {
227    // synchronize with internal class timer
228    totalTime_ = time;
229
230    // Call tick() for every object
231    // This could be done by registering (needs a factory..)
232    backgroundScene_->tick(time, deltaTime);
233    playerShip_->tick(time, deltaTime);
234
235
236    // Update the 'HUD'
237    updateStats();
238
239    // update the bullet positions
240    for (int i = 0; i < bulletsIndex_; i++)
241    {
242      bullets_[i]->mNode->translate(bullets_[i]->mSpeed*deltaTime);
243      bullets_[i]->mNode->yaw(Degree(deltaTime*100));
244      bullets_[i]->mNode->roll(Degree(deltaTime*300));
245    }
246
247    // HUMAN INTERFACE
248
249    using namespace OIS;
250
251    if(window_->isClosed())     return false;
252
253    //Need to capture/update each device
254    keyboard_->capture();
255    mouse_->capture();
256    if( joystick_ ) joystick_->capture();
257
258    bool buffJ = (joystick_) ? joystick_->buffered() : true;
259
260    //Check if one of the devices is not buffered
261    if( !mouse_->buffered() || !keyboard_->buffered() || !buffJ )
262    {
263      // one of the input modes is immediate, so setup what
264      // is needed for immediate movement
265      if (timeUntilNextToggle_ >= 0)
266        timeUntilNextToggle_ -= deltaTime;
267    }
268
269    // handle HID devices
270    if( processUnbufferedKeyInput() == false )
271        return false;
272    if( processUnbufferedMouseInput() == false )
273        return false;
274
275    // keep rendering
276    return true;
277  }
278
279
280  /**
281  * Adjust mouse clipping area.
282  * This method is called by Ogre without regards of tick()!
283  * Avoid doing too much in this call.
284  * @param rw render window
285  */
286  void RunManager::windowResized(RenderWindow* rw)
287  {
288    unsigned int width, height, depth;
289    int left, top;
290    rw->getMetrics(width, height, depth, left, top);
291
292    const OIS::MouseState &ms = mouse_->getMouseState();
293    ms.width = width;
294    ms.height = height;
295  }
296
297
298  /**
299  * Unattach OIS before window shutdown (very important under Linux).
300  * Again, avoid computing a lot in this function.
301  * @param rw Render Window
302  */
303  void RunManager::windowClosed(RenderWindow* rw)
304  {
305    //Only close for window that created OIS (the main window in these demos)
306    if( rw == window_ )
307    {
308      if( inputManager_ )
309      {
310        inputManager_->destroyInputObject( mouse_ );
311        inputManager_->destroyInputObject( keyboard_ );
312        inputManager_->destroyInputObject( joystick_ );
313
314        OIS::InputManager::destroyInputSystem(inputManager_);
315        inputManager_ = 0;
316      }
317    }
318  }
319
320  /**
321  * Processes the Keyboard input.
322  * TODO: Use listeners to improve performance.
323  * A lookup table should be implemented to bind any key to a specific action.
324  * @return Return true to keep rendering
325  */
326  bool RunManager::processUnbufferedKeyInput()
327  {
328    using namespace OIS;
329
330    if(keyboard_->isKeyDown(KC_A) || keyboard_->isKeyDown(KC_LEFT))
331      playerShip_->setSideThrust(1);
332    else if(keyboard_->isKeyDown(KC_D) || keyboard_->isKeyDown(KC_RIGHT))
333      playerShip_->setSideThrust(-1);
334    else
335      playerShip_->setSideThrust(0);
336
337    if(keyboard_->isKeyDown(KC_UP) || keyboard_->isKeyDown(KC_W) )
338      playerShip_->setMainThrust(1);
339    else if(keyboard_->isKeyDown(KC_DOWN) || keyboard_->isKeyDown(KC_S) )
340      playerShip_->setMainThrust(-1);
341    else
342      playerShip_->setMainThrust(0);
343
344    if (keyboard_->isKeyDown(KC_C))
345      playerShip_->setYThrust(1);
346    else if (keyboard_->isKeyDown(KC_SPACE))
347      playerShip_->setYThrust(-1);
348    else
349      playerShip_->setYThrust(0);
350
351    if( keyboard_->isKeyDown(KC_ESCAPE) || keyboard_->isKeyDown(KC_Q) )
352      return false;
353
354    if( keyboard_->isKeyDown(KC_F) && timeUntilNextToggle_ <= 0 )
355    {
356      statsOn_ = !statsOn_;
357      showDebugOverlay(statsOn_);
358      timeUntilNextToggle_ = 1;
359    }
360
361    if( keyboard_->isKeyDown(KC_T) && timeUntilNextToggle_ <= 0 )
362    {
363      switch(filtering_)
364      {
365      case TFO_BILINEAR:
366        filtering_ = TFO_TRILINEAR;
367        aniso_ = 1;
368        break;
369      case TFO_TRILINEAR:
370        filtering_ = TFO_ANISOTROPIC;
371        aniso_ = 8;
372        break;
373      case TFO_ANISOTROPIC:
374        filtering_ = TFO_BILINEAR;
375        aniso_ = 1;
376        break;
377      default: break;
378      }
379      MaterialManager::getSingleton().setDefaultTextureFiltering(filtering_);
380      MaterialManager::getSingleton().setDefaultAnisotropy(aniso_);
381
382      showDebugOverlay(statsOn_);
383      timeUntilNextToggle_ = 1;
384    }
385
386    if(keyboard_->isKeyDown(KC_SYSRQ) && timeUntilNextToggle_ <= 0)
387    {
388      std::ostringstream ss;
389      ss << "screenshot_" << ++screenShotCounter_ << ".png";
390      window_->writeContentsToFile(ss.str());
391      timeUntilNextToggle_ = 0.5;
392      debugText_ = "Saved: " + ss.str();
393    }
394
395    if(keyboard_->isKeyDown(KC_R) && timeUntilNextToggle_ <=0)
396    {
397      sceneDetailIndex_ = (sceneDetailIndex_+1)%3 ;
398      switch(sceneDetailIndex_) {
399          case 0 : camera_->setPolygonMode(PM_SOLID); break;
400          case 1 : camera_->setPolygonMode(PM_WIREFRAME); break;
401          case 2 : camera_->setPolygonMode(PM_POINTS); break;
402      }
403      timeUntilNextToggle_ = 0.5;
404    }
405
406    static bool displayCameraDetails = false;
407    if(keyboard_->isKeyDown(KC_P) && timeUntilNextToggle_ <= 0)
408    {
409      displayCameraDetails = !displayCameraDetails;
410      timeUntilNextToggle_ = 0.5;
411      if (!displayCameraDetails)
412        debugText_ = "";
413    }
414
415    // Print camera details
416    if(displayCameraDetails)
417      debugText_ = " | Speed = "
418            + StringConverter::toString(playerShip_->getSpeed());
419    // debugText_ = "P: " + StringConverter::toString(camera_
420    //      ->getDerivedPosition()) + " " + "O: "
421    //      + StringConverter::toString(camera_->getDerivedOrientation());
422
423    // Return true to continue rendering
424    return true;
425  }
426
427
428  /**
429  * Processes the Mouse input.
430  * TODO: Use listeners to improve performance.
431  * A lookup table should be implemented to bind ANY button or movement
432  * to a specific action.
433  * @return Return true to keep rendering
434  */
435  bool RunManager::processUnbufferedMouseInput()
436  {
437    using namespace OIS;
438
439    const MouseState &ms = mouse_->getMouseState();
440
441    // This is a 'hack' to show some flying barrels..
442    // Usually, the Bullet created by the ship should be managed
443    // by the physics engine..
444    if (ms.buttonDown(MB_Left) && !leftButtonDown_)
445    {
446      // Prevent continuous fire for the moment.
447      leftButtonDown_ = true;
448     
449      // let ship fire one shot with its only weapon (Barrels..)
450      Bullet *tempBullet = playerShip_->fire();
451
452      // resize array if neccessary (double the size then)
453      if (bulletsIndex_ >= bulletsSize_)
454      {
455        // redimension the array
456        Bullet **tempArray = new Bullet*[2*bulletsSize_];
457        for (int i = 0; i < bulletsSize_; i++)
458          tempArray[i] = bullets_[i];
459        bulletsSize_ *= 2;
460        delete bullets_;
461        bullets_ = tempArray;
462      }
463
464      // add the bullet to the list
465      bullets_[bulletsIndex_++] = tempBullet;
466
467    }
468    else if (!ms.buttons)
469      leftButtonDown_ = false;
470
471    // space ship steering. This should definitely be done in the steering object
472    // Simply give it the mouse movements.
473    playerShip_->turnUpAndDown(Radian(ms.Y.rel * mouseSensitivity_));
474    playerShip_->turnLeftAndRight(Radian(ms.X.rel * mouseSensitivity_));
475    //playerShip_->mRootNode->pitch(Degree(-ms.Y.rel * 0.13), Ogre::Node::TransformSpace::TS_LOCAL);
476    //playerShip_->mRootNode->yaw(Degree(-ms.X.rel * 0.13), Ogre::Node::TransformSpace::TS_PARENT);
477
478    // keep rendering
479    return true;
480  }
481
482  /**
483  * Show the debug overlay of desired.
484  * @param show Whether or not to show the debug overlay
485  */
486  void RunManager::showDebugOverlay(bool show)
487  {
488    if (debugOverlay_)
489    {
490      if (show)
491        debugOverlay_->show();
492      else
493        debugOverlay_->hide();
494    }
495  }
496
497
498  /**
499  * Show stats (e.g. FPS) in the left lower corner of the screen.
500  * Copied from the ExampleFrameListener.h in the Ogre SDK
501  */
502  void RunManager::updateStats(void)
503  {
504    static String currFps = "Current FPS: ";
505    static String avgFps = "Average FPS: ";
506    static String bestFps = "Best FPS: ";
507    static String worstFps = "Worst FPS: ";
508    static String tris = "Triangle Count: ";
509    static String batches = "Batch Count: ";
510
511    // update stats when necessary
512    try {
513      OverlayElement* guiAvg = OverlayManager::getSingleton()
514        .getOverlayElement("Core/AverageFps");
515      OverlayElement* guiCurr = OverlayManager::getSingleton()
516        .getOverlayElement("Core/CurrFps");
517      OverlayElement* guiBest = OverlayManager::getSingleton()
518        .getOverlayElement("Core/BestFps");
519      OverlayElement* guiWorst = OverlayManager::getSingleton()
520        .getOverlayElement("Core/WorstFps");
521
522      const RenderTarget::FrameStats& stats = window_->getStatistics();
523      guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));
524      guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));
525      guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)
526        +" "+StringConverter::toString(stats.bestFrameTime)+" ms");
527      guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)
528        +" "+StringConverter::toString(stats.worstFrameTime)+" ms");
529
530      OverlayElement* guiTris = OverlayManager::getSingleton()
531        .getOverlayElement("Core/NumTris");
532      guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
533
534      OverlayElement* guiBatches = OverlayManager::getSingleton()
535        .getOverlayElement("Core/NumBatches");
536      guiBatches->setCaption(batches
537        + StringConverter::toString(stats.batchCount));
538
539      OverlayElement* guiDbg = OverlayManager::getSingleton()
540        .getOverlayElement("Core/DebugText");
541      guiDbg->setCaption(debugText_);
542    }
543    catch(...) { /* ignore */ }
544  }
545
546
547
548  /**
549  * Simple camera creator.
550  * playerShip_Node->attachObject(camera_) should no be here! This is what the camera
551  * manager is for. Right now, this method should do just fine, setting the
552  * cam behind the ship.
553  */
554  void RunManager::createCamera(void)
555  {
556    camera_ = sceneMgr_->createCamera("PlayerCam");
557    playerShip_->getRootNode()->attachObject(camera_);
558    camera_->setNearClipDistance(5);
559    camera_->setPosition(Vector3(0,10,500));
560    camera_->lookAt(Vector3(0,0,0));
561  }
562
563  /**
564  * Simple viewport creator.
565  * TODO: fully understand the concept of viewports concerning orxnox.
566  * E.g. do we need splitscreen mode?
567  * For now the viewport uses the entire render window and is based on the one
568  * camera created so far.
569  */
570  void RunManager::createViewports(void)
571  {
572    // Create one viewport, entire window
573    Viewport* vp = window_->addViewport(camera_);
574    vp->setBackgroundColour(ColourValue(0,0,0));
575
576    // Alter the camera aspect ratio to match the viewport
577    camera_->setAspectRatio(
578      Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
579  }
580
581}
Note: See TracBrowser for help on using the repository browser.