Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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