/*
* ORXONOX - the hottest 3D action shooter ever to exist
*
*
* License notice:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
* Author:
* Reto Grieder
* Co-authors:
* ...
*/
#include "OgreVector3.h"
#include "OgreStringConverter.h"
#include "OgreRoot.h"
#include "OgreSceneManager.h"
#include "OgreSceneNode.h"
#include "OgreCamera.h"
#include "OgreViewport.h"
#include "OgreRenderWindow.h"
#include "OgreTextureManager.h"
#include "OgreMaterialManager.h"
#include "OgreLogManager.h"
#include "OgreWindowEventUtilities.h"
//Use this define to signify OIS will be used as a DLL
//(so that dll import/export macros are in effect)
#define OIS_DYNAMIC_LIB
#include
#include "ogre_control.h"
#include "orxonox_scene.h"
#include "orxonox_ship.h"
#include "inertial_node.h"
#include "weapon/bullet.h"
#include "weapon/bullet_manager.h"
#include "weapon/base_weapon.h"
#include "hud/hud_overlay.h"
#include "hud/test_overlay.h"
#include "run_manager.h"
namespace orxonox {
using namespace Ogre;
using namespace weapon;
using namespace hud;
/**
* RunManager is the basic control object during the game.
*
* The RunManger class is designed to actually "run" the main part of the
* game. The Idea is, that you could derive from the RunManager in order
* to distinguish between a first person shooter or a space craft shooter.
* RunManager loads and initialises everything in the scene (like the ship,
* the enemies in the scene, any scripts, the physics, window events,
* environment, HUD, etc.).
* It also captures any input from keyboard, mous, joystick (optional) or
* Ogre (window events).
*/
RunManager* RunManager::singletonPtr_s = NULL;
/**
* Contructor only needs the Root object.
*/
RunManager::RunManager()
: ogre_(NULL), window_(NULL), screenShotCounter_(0),
timeUntilNextToggle_(0), mouseSensitivity_(0.003), inputManager_(0),
mouse_(0), keyboard_(0), joystick_(0), statsOn_(true)
{
}
/**
* @param ogre_ The OgreControl object holding the render window and the Root
*/
void RunManager::initialise(OgreControl *ogre)
{
ogre_ = ogre;
window_ = ogre->getRenderWindow();
// SETTING UP THE SCENE
// create one new SceneManger
sceneMgr_ = ogre_->getRoot()->createSceneManager(ST_GENERIC, "Orxonox Scene");
// background scene (world objects, skybox, lights, etc.)
backgroundScene_ = new OrxonoxScene(sceneMgr_);
// BULLET LIST FOR THE TEST APPLICATION
// create a bullet manager
bulletManager_ = new BulletManager(sceneMgr_);
// PLAYER SPACESHIP
// Create a space ship object and its SceneNode.
// It should also be considered, that the ship should provide another Node
// for a camera to be attached (otherwise the spaceship in front of the
// ship would be very static, never moving at all).
// Construct a new spaceship and give it the node
playerShip_ = new OrxonoxShip(sceneMgr_->getRootSceneNode()
->createChildSceneNode("ShipNode", Vector3(20, 20, 20)));
// RESOURCE LOADING (using ResourceGroups if implemented)
// load all resources and create the entities by calling the initialise()
// methods for each object (no constructor initialisations!).
backgroundScene_->initialise();
playerShip_->initialise();
// CAMERA AND VIEWPORT
// create camera and viewport
createCamera();
createViewports();
// create HUD
hud_ = new hud::TestOverlay(window_);
hud_->show();
// Set default mipmap level (NB some APIs ignore this)
TextureManager::getSingleton().setDefaultNumMipmaps(5);
// HUMAN INTERFACE
using namespace OIS;
LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");
ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
window_->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
inputManager_ = InputManager::createInputSystem( pl );
// Create all devices (We only catch joystick exceptions here,
// as, most people have Key/Mouse)
keyboard_ = static_cast(inputManager_
->createInputObject( OISKeyboard, false ));
mouse_ = static_cast(inputManager_
->createInputObject( OISMouse, false ));
try {
joystick_ = static_cast(inputManager_
->createInputObject( OISJoyStick, false ));
}
catch(...) {
joystick_ = 0;
}
//Set initial mouse clipping size
windowResized(window_);
//showDebugOverlay(true);
// REGISTER THIS OBJECT AS A WINDOW EVENT LISTENER IN OGRE
// It will then receive events liek windowClosed, windowResized, etc.
WindowEventUtilities::addWindowEventListener(window_, this);
}
/**
* Standard destructor.
* Removes this object as a window event listener and deletes all created
* variables.
*/
RunManager::~RunManager()
{
//Remove ourself as a Window listener
WindowEventUtilities::removeWindowEventListener(window_, this);
windowClosed(window_);
if (backgroundScene_)
delete backgroundScene_;
if (playerShip_)
delete playerShip_;
if (bulletManager_)
delete bulletManager_;
if (hud_)
delete hud_;
}
/**
* Method to compute anything between 2 frames.
*
* Everything that needs to be computed during the games happens right here.
* The only exception are the listeners (which should only set variables,
* not actually do something).
*
* @param time Absolute play time
* @param deltaTime Time passed since last frame
* @return Return false to end rendering
*/
bool RunManager::tick(unsigned long time, float deltaTime)
{
// synchronize with internal class timer
totalTime_ = time;
// Call tick() for every object
// This could be done by registering (needs a factory..)
backgroundScene_->tick(time, deltaTime);
playerShip_->tick(time, deltaTime);
// Update the HUD
Ogre::String tempStr = " | Speed = "
+ StringConverter::toString(playerShip_->getSpeed())
+ " | Left Ammo = "
+ StringConverter::toString(playerShip_
->getMainWeapon()->getAmmoState())
+ " | Ammo stock = "
+ StringConverter::toString(playerShip_->getAmmoStock());
hud_->setDebugText(tempStr);
hud_->tick(time, deltaTime);
// update the bullet positions
bulletManager_->tick(time, deltaTime);
// HUMAN INTERFACE
using namespace OIS;
if(window_->isClosed()) return false;
//Need to capture/update each device
keyboard_->capture();
mouse_->capture();
if( joystick_ ) joystick_->capture();
bool buffJ = (joystick_) ? joystick_->buffered() : true;
//Check if one of the devices is not buffered
if( !mouse_->buffered() || !keyboard_->buffered() || !buffJ )
{
// one of the input modes is immediate, so setup what
// is needed for immediate movement
if (timeUntilNextToggle_ >= 0)
timeUntilNextToggle_ -= deltaTime;
}
// handle HID devices
if( processUnbufferedKeyInput() == false )
return false;
if( processUnbufferedMouseInput() == false )
return false;
// keep rendering
return true;
}
SceneManager& RunManager::getSceneManager()
{
return *sceneMgr_;
}
SceneManager* RunManager::getSceneManagerPtr()
{
return sceneMgr_;
}
BulletManager* RunManager::getBulletManagerPtr()
{
return bulletManager_;
}
int RunManager::getAmmunitionID(const Ogre::String &ammoName)
{
Ogre::String ammoTypes[] = { "Energy Cell", "Barrel", "Lead Shot" };
int ammoTypesLength = 3;
for (int i = 0; i < ammoTypesLength; i++)
{
if (ammoTypes[i] == ammoName)
return i;
}
return -1;
}
int RunManager::getNumberOfAmmos()
{
return 3;
}
/**
* Adjust mouse clipping area.
* This method is called by Ogre without regards of tick()!
* Avoid doing too much in this call.
* @param rw render window
*/
void RunManager::windowResized(RenderWindow* rw)
{
unsigned int width, height, depth;
int left, top;
rw->getMetrics(width, height, depth, left, top);
const OIS::MouseState &ms = mouse_->getMouseState();
ms.width = width;
ms.height = height;
}
/**
* Unattach OIS before window shutdown (very important under Linux).
* Again, avoid computing a lot in this function.
* @param rw Render Window
*/
void RunManager::windowClosed(RenderWindow* rw)
{
//Only close for window that created OIS (the main window in these demos)
if( rw == window_ )
{
if( inputManager_ )
{
inputManager_->destroyInputObject( mouse_ );
inputManager_->destroyInputObject( keyboard_ );
inputManager_->destroyInputObject( joystick_ );
OIS::InputManager::destroyInputSystem(inputManager_);
inputManager_ = 0;
}
}
}
/**
* Processes the Keyboard input.
* TODO: Use listeners to improve performance.
* A lookup table should be implemented to bind any key to a specific action.
* @return Return true to keep rendering
*/
bool RunManager::processUnbufferedKeyInput()
{
using namespace OIS;
if(keyboard_->isKeyDown(KC_A) || keyboard_->isKeyDown(KC_LEFT))
playerShip_->setSideThrust(1);
else if(keyboard_->isKeyDown(KC_D) || keyboard_->isKeyDown(KC_RIGHT))
playerShip_->setSideThrust(-1);
else
playerShip_->setSideThrust(0);
if(keyboard_->isKeyDown(KC_UP) || keyboard_->isKeyDown(KC_W) )
playerShip_->setMainThrust(1);
else if(keyboard_->isKeyDown(KC_DOWN) || keyboard_->isKeyDown(KC_S) )
playerShip_->setMainThrust(-1);
else
playerShip_->setMainThrust(0);
if (keyboard_->isKeyDown(KC_C))
playerShip_->setYThrust(1);
else if (keyboard_->isKeyDown(KC_SPACE))
playerShip_->setYThrust(-1);
else
playerShip_->setYThrust(0);
if (keyboard_->isKeyDown(KC_G))
playerShip_->getMainWeapon()->addAction(BaseWeapon::RELOAD);
if( keyboard_->isKeyDown(KC_ESCAPE) || keyboard_->isKeyDown(KC_Q) )
return false;
if( keyboard_->isKeyDown(KC_F) && timeUntilNextToggle_ <= 0 )
{
statsOn_ = !statsOn_;
timeUntilNextToggle_ = 1;
}
if(keyboard_->isKeyDown(KC_SYSRQ) && timeUntilNextToggle_ <= 0)
{
std::ostringstream ss;
ss << "screenshot_" << ++screenShotCounter_ << ".png";
window_->writeContentsToFile(ss.str());
timeUntilNextToggle_ = 0.5;
}
// Return true to continue rendering
return true;
}
/**
* Processes the Mouse input.
* TODO: Use listeners to improve performance.
* A lookup table should be implemented to bind ANY button or movement
* to a specific action.
* @return Return true to keep rendering
*/
bool RunManager::processUnbufferedMouseInput()
{
using namespace OIS;
const MouseState &ms = mouse_->getMouseState();
if (ms.buttonDown(MB_Left))
playerShip_->getMainWeapon()->primaryFireRequest();
if (ms.buttonDown(MB_Right))
playerShip_->getMainWeapon()->secondaryFireRequest();
playerShip_->turnUpAndDown(Radian(ms.Y.rel * mouseSensitivity_));
playerShip_->turnLeftAndRight(Radian(ms.X.rel * mouseSensitivity_));
// keep rendering
return true;
}
/**
* Show an overlay desired.
* @param show Whether or not to show the debug overlay
*/
void RunManager::showDebugOverlay(bool show)
{
if (hud_)
{
if (show)
hud_->show();
else
hud_->hide();
}
}
/**
* Simple camera creator.
* playerShip_Node->attachObject(camera_) should not be here! This is what
* the camera manager is for. Right now, this method should do just fine,
* setting the cam behind the ship.
*/
void RunManager::createCamera()
{
camera_ = sceneMgr_->createCamera("PlayerCam");
playerShip_->getRootNode()->getSceneNode()->attachObject(camera_);
camera_->setNearClipDistance(5);
camera_->setPosition(Vector3(0,10,500));
camera_->lookAt(Vector3(0,0,0));
}
/**
* Simple viewport creator.
* For now the viewport uses the entire render window and is based on the one
* camera created so far.
*/
void RunManager::createViewports()
{
// Create one viewport, entire window
Viewport* vp = window_->addViewport(camera_);
vp->setBackgroundColour(ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
camera_->setAspectRatio(
Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}
RunManager* RunManager::createSingleton()
{
if (singletonPtr_s)
return NULL;
singletonPtr_s = new RunManager();
return singletonPtr_s;
}
void RunManager::destroySingleton()
{
if (singletonPtr_s)
delete singletonPtr_s;
}
RunManager& RunManager::getSingleton()
{
return *singletonPtr_s;
}
RunManager* RunManager::getSingletonPtr()
{
return singletonPtr_s;
}
}