Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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