Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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