Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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