Introduction
In this article, I introduce a solution of 3D RPG based on Ogre Graphics Engine, ODE Physics Engine, CEGUI, and other tools. The framework is described and the full resource and source code is on https://github.com/lxdfigo/Space-Knight.
Background
Space Knight is a cartoon I watched when I was a child and I'm also a game fan. So I use what I learned before to develop the cartoon to an RPG. Here, displaying what lib I used in my game:
- Ogre: I use Ogre as the Graphics Engine. It can choose DirectX or OpenGL to render the scene.
- OED: I use OgreOde which combines the Ogre with the ODE to build the physical world in my game.
- CEGUI: It is used to construct the UI in the game such as main menu, trade menu, function menu, etc.
- 3D Max: The models in our game is built by 3D Max and is exported by a plugin.
- DirectShow and Fmod: They are used to play the video and the audio.
Using the Code
As mentioned before, the application bases on several libs. Here is the UML figure of my game framework.
There are several modules in the application. There are Mission Module, Role Module, AI Module, UI Module, Tool Module and Media Module.
The Mission Module controls the mission of the game and it contains the BaseMission
class, FirstMission
class, etc. Each class represents a mission in the game. The base class also controls the most modules.
The Role Module controls the players in the game such as the main player, space knight, the monster Lada, the NPC, etc. These entities are managed by the entity manager and are checked if they have collision in each frame. The part of Role Module is also controlled by the AI Module.
The AI Module uses state machine to simulate the role's AI. Each role having the AI has its own state class and the class defines its behaviors. It can be easily changed and extended.
The UI Module using CEGUI to display the UI of the game. It receives the input from the user and posts the message to other modules. It uses OIS to receive the keyboard message and the mouse message. Each menu on the screen is a script file rendered by CEGUI.
The Tool Module controls the tools, medicines and other objects in the game such as the chest on the road or the opening door. Most tools are built by the status from the XML file.
The Media Module is a simple adapter of Fmod and DirectShow. It plays the sound of the battle or the background and the video of the opening play.
The base class of the mission contains a lot of members and functions. It uses the UI module to display the menu, the Media module to play the sound, the Role module to update the entities. It also builds the graphic world and the physical world. It has the function to move to the next mission, load the saved mission or game over.
The state machine shows it contains three main states - the previous state, the current state and the global state. The state has four behaviors - Enter
, Exit
, Execute
, and OnMessage
. If a role receives a message and it gives to the state machine, it lets the current state execute and transfer to the next state.
class BaseMission:
public OgreOde::CollisionListener,
public OgreOde::StepListener,
public OgreOde::TriangleMeshRayListener
{
public:
....
OgreOde::World *mWorld;
OgreOde::Space *mSpace;
OgreOde::StepHandler *mStepper;
OgreOde::TriangleMeshGeometry* terrainTriMeshGeom;
OgreOde::InfinitePlaneGeometry *mGround;
GameFrame *gameFrame;
Ogre::Root* mRoot;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
CEGUI::System* mGUISystem;
FrameListener* mFrameListener;
BaseMissionListener* mMissionListener;
GuiListener *mGuiListener;
Overlay *talkOverlay,*gameOverlay,*blackOverlay,*loadingOverlay,*missionIntruOverlay;
CEGUI::Window* gameSheet,* opSheet,* quitSheet,
* gameOverSheet,* loadSheet,* intruduceSheet,
* useButton,*noUseButton,* currentPackage;
std::vector<AnimationState *> animationStates;
std::vector<Model *> mModels;
std::vector<OgreOde::Geometry*> mGeoms;
std::vector<SceneNode*> nodes;
std::vector<StaticThing*> staticThings;
std::vector<Role*> monsters;
Role *mainModel;
BaseSound *mSound;
SceneNode * _rocket_node_explosion;
ParticleSystem * _rocketParticles_explosion;
public :
BaseMission(Ogre::RenderWindow* mW, Ogre::Root* mR, Ogre::Camera* mC,
Ogre::SceneManager* mS,CEGUI::System* mG,GameFrame *);
virtual void Render();
virtual void Clean();
virtual void InitObjects();
virtual void createFrameListener();
virtual void NextMission();
virtual void upDate();
virtual void createScene();
virtual void UpdateGUI(void);
virtual void initDemoEventWiring(void);
...
Ogre::SceneManager* getSceneManager(void) const { return mSceneMgr; }
Ogre::RenderWindow* getRenderWindow(void) const { return mWindow; }
void resetParticleSystem(Ogre::ParticleSystem *ps, bool enable, const Ogre::Real delay);
virtual void GameOver();
void LoadGame(int i);
};
template <class entity_type>
class StateMachine
{
private:
entity_type *m_pOwner;
State<entity_type> *m_pCurrentState;
State<entity_type> *m_pPreviousState;
State<entity_type> *m_pGlobalState;
public:
StateMachine(entity_type *owner):m_pOwner(owner),
m_pCurrentState(NULL),m_pPreviousState(NULL),m_pGlobalState(NULL){}
void SetCurrentState(State<entity_type> *s){m_pCurrentState = s;}
void SetPreviousState(State<entity_type> *s){m_pPreviousState = s;}
void SetGlobalState(State<entity_type> *s){m_pGlobalState = s;}
...
};
template <class entity_type>
class State
{
public:
virtual bool OnMessage(entity_type *,Telegram &msg) = 0;
virtual void Enter(entity_type *) = 0;
virtual void Exit(entity_type *) = 0;
virtual void Execute(entity_type *) = 0;
virtual ~State(){}
};
Operation and Result
The operation of the game:
- Move: W, A, S, D
- Fire: mouse, Z, C, V
- Mission Pass: Y
- Menu: F1
Our game has seven missions which include two boss mission and one transfer mission. Shown here are some pictures of my game.
The main menu of the game.
The player beat a monster.
History
- 18th April, 2013: Initial version