Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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