Table of contents
Introduction
Ok, you have worked yourself through the all the tutorials. From just displaying this little Ogre Head, over walking with a robot and you finished with the Advanced Framework tutorial.
The next step now would be to work right on the next World of WarCraft combined with some features of Minecraft but with the graphic quality of Crysis!
Good Idea! Or you start with me on a little game of Astroids, based on the Advanced Ogre Framework combine things we have seen in the previous tutorials, and build our first game.
And yes, this is my first Ogre Game to, I just write this tutorial next to it!
So what are our goals.
- Keep it simple
- Keep it really simple
- Yes really simple, but we want a playable game
Very important is to understand, that with every level of complexity we add, the number of possible solutions increase. There are not so many ways to draw an Ogre head, and then do nothing but exit the program. But there are all ready countless ways to do something simple like an Astroids clone. So what we do here isn't the only way, heck I'm quite sure it isn't somewhere near the "best" way.
What I want to show and give you is.
- Amount of work necessary for this little game, so you can plan your project based on your resources
- A list of problems I encountered, and how I solved them
- There are still rough edges, if you want you can try to iron them out and get used to this great engine
So lets start
Architecture
If have decided to work with 4 classes.
- Ogrestroid, is a copy of GameState.hpp
So here we have the basic game control, input management, gui and we steer the other classes
- Ship
A class which will control the player ship
- Meteor
A singleton class which will control all the roaming ogre heads
- Projectile
Also a singleton class which we use to handle the gunfire of the ship
We also have a structure FlyingObject which will store Infos about the things we let fly over the screen.
This would be
- be created
- collide against a other flying thing
- and be removed
and then inherited all the other class from this class.
Ship.hpp
#pragma once #include <OgreManualObject.h> #include <OgreMaterialManager.h> #include "AdvancedOgreFramework.hpp" #include "OgreParticleSystem.h" #include "Meteor.hpp" using namespace Ogre; class Ship { public: Ship(void); ~Ship(void); void move( double timeSinceLastFrame); void setSceneManager( SceneManager* pSceneMgr){ m_pSceneMgr = pSceneMgr;} void create(); void turnLeft(); void turnRight(); void accelerate(bool todo); void stop(); void die(); void reset(); FlyingObject getShipInfo(){return m_shipInfo;}; void setGameField(Real x, Real y){ m_fieldX = x; m_fieldY = y; } private: Entity* m_pShipEntity; SceneNode* m_pShipNode; FlyingObject m_shipInfo; Real m_fieldX, m_fieldY; Vector3 m_ShipSpeed; Degree m_ShipOrientation; bool m_ShipAccelerate; Real m_ShipAcceleration; Real m_ShipMaxSpeed; Degree m_ShipRotateSpeed; Degree m_ShipRotation; //to lean into the curve bool m_isTurningLeft; bool m_isTurningRight; bool m_isStillInTurnLeft; bool m_isStillInTurnRight; SceneManager* m_pSceneMgr; double m_timeSinceLastFrame; };
Ship.cpp
#include "Ship.hpp" #include "HelperFunctions.h" using namespace Ogre; Ship::Ship(void) { m_fieldX = 400; m_fieldY = 200; } Ship::~Ship(void) { // Destroy all the attached objects DestroyAllAttachedMovableObjects(m_pShipNode); m_pSceneMgr->getRootSceneNode()->removeChild(m_pShipNode); } void Ship::create() { // Create the entity m_pShipEntity = m_pSceneMgr->createEntity("RZR-002.mesh"); // Create the scene node m_pShipNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 0, -100.0f)); m_pShipNode->attachObject(m_pShipEntity); m_shipInfo.mpNode = m_pShipNode; m_pShipNode->setScale(3, 3, 3); m_pShipNode->pitch(Radian(Degree(90))); m_pShipNode->yaw(Radian(Degree(90))); m_ShipOrientation = 0.0; m_ShipAccelerate = false; m_ShipAcceleration = 0.001; m_ShipMaxSpeed = 0.9; m_ShipSpeed = Vector3::ZERO; m_ShipRotateSpeed = 0.2; m_ShipRotation = 0.0; m_isTurningLeft = false; m_isTurningRight = false; m_isStillInTurnLeft = false; m_isStillInTurnRight = false; } void Ship::die() { //TODO //A explosion would be nice ;) m_pShipNode->setVisible(false); } void Ship::reset() { m_pShipNode->setPosition(0,0,-100.0f); m_pShipNode->setVisible(true); m_ShipSpeed = Vector3::ZERO; } void Ship::move(double timeSinceLastFrame) { m_timeSinceLastFrame = timeSinceLastFrame; if( m_ShipAccelerate ) { Real xAcc = Math::Cos(m_ShipOrientation.valueRadians()) * m_ShipAcceleration * m_timeSinceLastFrame; Real yAcc = Math::Sin(m_ShipOrientation.valueRadians()) * m_ShipAcceleration * m_timeSinceLastFrame; //TODO //We don't want to go over max speed, there may be a better way to check this! if( (Math::Abs(m_ShipSpeed.x) + Math::Abs(m_ShipSpeed.y) + xAcc) < m_ShipMaxSpeed ) m_ShipSpeed.x += xAcc; if( (Math::Abs(m_ShipSpeed.x) + Math::Abs(m_ShipSpeed.y) + yAcc) < m_ShipMaxSpeed ) m_ShipSpeed.y += yAcc; } //Move Vector3 shipMovement = m_ShipSpeed * timeSinceLastFrame; m_pShipNode->translate(shipMovement); //Are we out of the Game Field? Vector3 position = m_pShipNode->getPosition(); if( position.x > m_fieldX) position.x = -m_fieldX; if( position.x < -m_fieldX) position.x = m_fieldX; if( position.y > m_fieldY) position.y = -m_fieldY; if( position.y < -m_fieldY) position.y = m_fieldY; if( position != m_pShipNode->getPosition()) m_pShipNode->setPosition(position); //Now we want to lean into the curve if(m_isTurningLeft) //We only need to lean, if we are not allready doing this { if(!m_isStillInTurnLeft) { m_pShipNode->roll(Degree(-20)); m_isStillInTurnLeft = true; } m_isTurningLeft = false; //If on the next frame Ship::turnLeft() isn't called we will go back to normal } else if(m_isStillInTurnLeft) //End of a turn? { //Back to normal ;) m_pShipNode->roll(Degree(20)); m_isStillInTurnLeft = false; } if(m_isTurningRight) //We only need to lean, if we are not allready doing this { if(!m_isStillInTurnRight) { m_pShipNode->roll(Degree(20)); m_isStillInTurnRight = true; } m_isTurningRight = false; //If on the next frame Ship::turnRight() isn't called we will go back to normal } else if(m_isStillInTurnRight) //End of a turn? { //Back to normal ;) m_pShipNode->roll(Degree(-20)); m_isStillInTurnRight = false; } //Turn m_pShipNode->roll(m_ShipRotation, Ogre::Node::TS_WORLD); m_ShipRotation = 0.0; m_shipInfo.mOrientation = m_ShipOrientation; } void Ship::turnLeft() { m_ShipOrientation += m_ShipRotateSpeed * m_timeSinceLastFrame; m_ShipRotation = m_ShipRotateSpeed * m_timeSinceLastFrame; if( m_ShipOrientation > Degree(360.0f)) m_ShipOrientation -= Degree(360.0f); if( m_ShipOrientation < Degree(0.0f)) m_ShipOrientation += Degree(360.0f); m_isTurningLeft = true; } void Ship::turnRight() { m_ShipOrientation -= m_ShipRotateSpeed * m_timeSinceLastFrame; m_ShipRotation = -1 * m_ShipRotateSpeed * m_timeSinceLastFrame; if( m_ShipOrientation > Degree(360.0f)) m_ShipOrientation -= Degree(360.0f); if( m_ShipOrientation < Degree(0.0f)) m_ShipOrientation += Degree(360.0f); m_isTurningRight = true; } void Ship::accelerate(bool todo) { m_ShipAccelerate = todo; } void Ship::stop() { m_ShipAccelerate = false; m_ShipSpeed.x = 0; m_ShipSpeed.y = 0; }