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.

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.

 Inheritance
If you want, you can create a basic class FlyingObject, implement all the basic things a FlyingObject can do.

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;
}