Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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