Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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