Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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