【译】一个基于Ogre和ODE的3D RPG
原文地址:http://www.codeproject.com/Articles/479054/A-D-RPG-Based-on-Ogre-and-ODE
版权:作者版权声明为http://www.codeproject.com/info/cpol10.aspx,可以翻译
简介
在这篇文章里,我介绍一个用Ogre图形引擎、ODE物理引擎和CEGUI等开发的3DRPG。框架和源代码资源在这里https://github.com/lxdfigo/Space-Knight。
背景
太空骑士是一个我孩子时期看的动画片,我还是一个游戏粉丝。所以我用我学到的知识把这个卡通开发成了RPG。这里是我用在游戏里面的Lib:
· Ogre : 我用它作为图形引擎。它可以选择DirectX或是OpenGL来绘制屏幕。
· OED:我用它和Ogre一起来构建游戏的物理世界。
· CEGUI:它用来做游戏的主菜单、交易菜单和功能菜单。
· 3D Max:游戏中的模型是在3DMax里面做的然后通过插件导出
· DirectShow and Fmod: 它们用来播放音频和视频
使用代码
下面是游戏框架的UML图。
游戏有几个模块,分别是任务、角色、AI、UI、工具和媒体模块。
任务模块控制着游戏的任务并且它有BaseMission 和FirstMission 等类。每一个类代表游戏的一个任务。基类控制着主要模块。
角色模块控制着游戏的角色比如主玩家、太空骑士、怪物Lada和NPC等等。他们是由entitymanager管理的并会在每一帧检测是否发生碰撞。角色模块也受到AI模块的控制;
AI模块使用状态机来模拟角色的人工智能。每个有AI的角色拥有人工智能有其自己的状态类和行为。它可以很容易地改变和扩展。
UI模块使用CEGUI显示游戏的UI。它接收来自用户的输入,把消息传递其他模块。它使用OIS接收键盘消息和鼠标消息。每个被CEGUI绘制在屏幕上的菜单都是一个脚本文件。
媒体模块就是Fmod和DirectShow的一个简单适配器。播放战斗和背景的声音和开场动画。
任务的基类包含一大堆成员和函数。它使用了UI模块来展示菜单,媒体模块来播放声音,角色模块来更新实体。它还构建了图形世界和物理世界。它还有函数来跳到下一个任务,加载保存的任务或者结束游戏。
状态机有3个主要状态:过去态、现在态和全局态。每个状态有4个行为Enter、Exit、Execute和 OnMessage。如果一个角色收到一条消息,会让状态机的当前状态执行并且转到下一个状态去。
//
//Here is the Base Mission class
//
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 animationStates;
std::vector mModels;
std::vector mGeoms;
std::vector nodes;
std::vector staticThings;
std::vector 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);
};
//
// Here is part of the state machine of the AI in the game.
//
template
class StateMachine
{
private:
entity_type *m_pOwner;
State *m_pCurrentState;
State *m_pPreviousState;
State *m_pGlobalState;
public:
StateMachine(entity_type *owner):m_pOwner(owner),
m_pCurrentState(NULL),m_pPreviousState(NULL),m_pGlobalState(NULL){}
void SetCurrentState(State *s){m_pCurrentState = s;}
void SetPreviousState(State *s){m_pPreviousState = s;}
void SetGlobalState(State *s){m_pGlobalState = s;}
...
};
template
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(){}
};
操作和结果
游戏操作:
l 移动:W, A, S, D
l 开火: 鼠标, Z, C, V
l 任务通关: Y
l 菜单: F1
游戏一共有7个任务,2个boss任务还有一个运送任务。下面是一些游戏的截图。
游戏的主菜单
玩家击败了一个怪兽