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
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"
58#include "weapon/weapon_manager.h"
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)
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  {
[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    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
[161]118    // PLAYER SPACESHIP
[157]119
[161]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).
[157]131
[161]132    // Construct a new spaceship and give it the node
133    playerShip_ = new OrxonoxShip(sceneMgr_, sceneMgr_->getRootSceneNode()
[177]134      ->createChildSceneNode("ShipNode", Vector3(20, 20, 20)), bulletManager_);
[157]135
136
[161]137    // RESOURCE LOADING (using ResourceGroups if implemented)
[157]138
[161]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();
[157]143
144
[161]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.
[157]150
[161]151    // create camera and viewport
152    createCamera();
153    createViewports();
[157]154
155
[161]156    // Set default mipmap level (NB some APIs ignore this)
157    TextureManager::getSingleton().setDefaultNumMipmaps(5);
[157]158
[161]159   
[157]160
[161]161    // HUMAN INTERFACE
[157]162
[161]163    using namespace OIS;
[157]164
[161]165    debugOverlay_ = OverlayManager::getSingleton()
166      .getByName("Core/DebugOverlay");
[157]167
[161]168    LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
169    ParamList pl;
170    size_t windowHnd = 0;
171    std::ostringstream windowHndStr;
[157]172
[161]173    window_->getCustomAttribute("WINDOW", &windowHnd);
174    windowHndStr << windowHnd;
175    pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
[157]176
[161]177    inputManager_ = InputManager::createInputSystem( pl );
[157]178
[161]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    }
[157]192
[161]193    //Set initial mouse clipping size
194    windowResized(window_);
[157]195
[161]196    showDebugOverlay(true);
[157]197
[161]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  }
[157]202
[161]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_);
[157]213
[161]214    if (backgroundScene_)
215      delete backgroundScene_;
216    if (playerShip_)
217      delete playerShip_;
[177]218    if (bulletManager_)
219      delete bulletManager_;
[157]220
[177]221    WeaponManager::destroyWeapons();
222
[161]223    // clean up the bullet list
[177]224    /*for (int i = 0; i < bulletsIndex_; i++)
[161]225      delete bullets_[i];
[177]226    delete bullets_;*/
[161]227  }
[157]228
229
[161]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;
[157]245
[161]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);
[157]250
251
[161]252    // Update the 'HUD'
253    updateStats();
[157]254
[161]255    // update the bullet positions
[177]256    bulletManager_->tick(time, deltaTime);
257
258    /*for (int i = 0; i < bulletsIndex_; i++)
[161]259    {
[169]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));
[177]263    }*/
[157]264
[161]265    // HUMAN INTERFACE
[157]266
[161]267    using namespace OIS;
[157]268
[161]269    if(window_->isClosed())     return false;
[157]270
[161]271    //Need to capture/update each device
272    keyboard_->capture();
273    mouse_->capture();
274    if( joystick_ ) joystick_->capture();
[157]275
[161]276    bool buffJ = (joystick_) ? joystick_->buffered() : true;
[157]277
[161]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    }
[157]286
[161]287    // handle HID devices
288    if( processUnbufferedKeyInput() == false )
289        return false;
290    if( processUnbufferedMouseInput() == false )
291        return false;
[157]292
[161]293    // keep rendering
294    return true;
295  }
[157]296
297
[161]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);
[157]309
[161]310    const OIS::MouseState &ms = mouse_->getMouseState();
311    ms.width = width;
312    ms.height = height;
313  }
[157]314
315
[161]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)
[157]322  {
[161]323    //Only close for window that created OIS (the main window in these demos)
324    if( rw == window_ )
[157]325    {
[161]326      if( inputManager_ )
327      {
328        inputManager_->destroyInputObject( mouse_ );
329        inputManager_->destroyInputObject( keyboard_ );
330        inputManager_->destroyInputObject( joystick_ );
[157]331
[161]332        OIS::InputManager::destroyInputSystem(inputManager_);
333        inputManager_ = 0;
334      }
[157]335    }
336  }
337
[161]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;
[157]347
[161]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);
[157]354
[161]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);
[157]361
[161]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);
[159]368
[161]369    if( keyboard_->isKeyDown(KC_ESCAPE) || keyboard_->isKeyDown(KC_Q) )
370      return false;
[157]371
[161]372    if( keyboard_->isKeyDown(KC_F) && timeUntilNextToggle_ <= 0 )
373    {
374      statsOn_ = !statsOn_;
375      showDebugOverlay(statsOn_);
376      timeUntilNextToggle_ = 1;
377    }
[157]378
[161]379    if( keyboard_->isKeyDown(KC_T) && timeUntilNextToggle_ <= 0 )
[157]380    {
[161]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;
[157]402    }
403
[161]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    }
[157]412
[161]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    }
[157]423
[161]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_ = "";
[157]431    }
432
[161]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;
[157]443  }
444
445
[161]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;
[157]456
[161]457    const MouseState &ms = mouse_->getMouseState();
[157]458
[161]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;
[177]466
467      playerShip_->fire();
[161]468     
469      // let ship fire one shot with its only weapon (Barrels..)
[177]470      /*Bullet *tempBullet = playerShip_->fire();
[157]471
[161]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      }
[157]483
[161]484      // add the bullet to the list
[177]485      bullets_[bulletsIndex_++] = tempBullet;*/
[157]486
487    }
[161]488    else if (!ms.buttons)
489      leftButtonDown_ = false;
[157]490
[161]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);
[157]497
[161]498    // keep rendering
499    return true;
[157]500  }
501
[161]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)
[157]507  {
[161]508    if (debugOverlay_)
509    {
510      if (show)
511        debugOverlay_->show();
512      else
513        debugOverlay_->hide();
514    }
[157]515  }
516
517
[161]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: ";
[157]530
[161]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");
[157]541
[161]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");
[157]549
[161]550      OverlayElement* guiTris = OverlayManager::getSingleton()
551        .getOverlayElement("Core/NumTris");
552      guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));
[157]553
[161]554      OverlayElement* guiBatches = OverlayManager::getSingleton()
555        .getOverlayElement("Core/NumBatches");
556      guiBatches->setCaption(batches
557        + StringConverter::toString(stats.batchCount));
[157]558
[161]559      OverlayElement* guiDbg = OverlayManager::getSingleton()
560        .getOverlayElement("Core/DebugText");
561      guiDbg->setCaption(debugText_);
562    }
563    catch(...) { /* ignore */ }
[157]564  }
565
566
567
[161]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");
[189]577    playerShip_->getRootNode()->getSceneNode()->attachObject(camera_);
[161]578    camera_->setNearClipDistance(5);
579    camera_->setPosition(Vector3(0,10,500));
580    camera_->lookAt(Vector3(0,0,0));
581  }
[157]582
[161]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));
[157]595
[161]596    // Alter the camera aspect ratio to match the viewport
597    camera_->setAspectRatio(
598      Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
599  }
600
[157]601}
Note: See TracBrowser for help on using the repository browser.