Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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