用OGRE1.74搭建游戲框架(二)--添加菜單


在上一節中,已經把OGRE的一個框架搭出來了,而且用的是一個單例模式,這樣就意味着我們在后面的狀態模式中可以很容易的就使用OGRE來幫我們進行圖形繪制。

 

首先,寫一個所有游戲狀態的基類,因為我們大體可以抽象出所有游戲狀態都應該有:

1.進入這個狀態時應該做一些准備工作

2.退出這個狀態時應該刪除某些東西

3.暫停和繼續時的一些動作。

4.更新

 

而一個游戲里有很多狀態的切換,而我們又不想讓一個狀態知道另一個狀態的存在,於是我們就要有一個統一管理這些狀態的一個類,這樣就能讓這些狀態之間解耦。(如果不這樣做,比如說我想從菜單狀態切換到游戲開始狀態,那么我得在開始菜單中保存一個指向游戲開始狀態的指針,而游戲開始狀態想切到其它的狀態也得這么做。)

因此我們寫一個狀態管理類,它實現一個狀態監聽接口。

狀態管理用一個棧來存儲所有的狀態,當從當前狀態切換到另一個狀態時,就把棧頂的狀態取出,並調用它的Exit()函數,並Pop出去,然后再初始化新的狀態,並調用新狀態的Enter()函數。

void CGameStateManager::ChangeGameState(CGameState* state)
{
if (!m_ActiveStateStack.empty())
{
m_ActiveStateStack.back()->Exit();
m_ActiveStateStack.pop_back();
}

m_ActiveStateStack.push_back(state);
Init(state);
m_ActiveStateStack.back()->Enter();
}



 

GameState.h文件如下:

/********************************************************************
created: 2012/02/25
created: 25:2:2012 15:05
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\GameState.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: GameState
file ext: h
author: Star

purpose: the parent of all the game state
********************************************************************
*/

#ifndef _ZH_GAMESTATE_H_
#define _ZH_GAMESTATE_H_

#pragma once

#include "OgreFramework.h"

class CGameState;

class CGameStateListener
{
public:
CGameStateListener(){};
virtual ~CGameStateListener(){};

virtual void ManageGameState(Ogre::String stateName, CGameState* state) = 0;

virtual CGameState* FindByName(Ogre::String stateName) = 0;
virtual void ChangeGameState(CGameState* state) = 0;
virtual bool PushGameState(CGameState* state) = 0;
virtual void PopGameState() = 0;
virtual void PauseCurGameState() = 0;
virtual void Shutdown() = 0;
virtual void PopAllAndPushGameState(CGameState* state) = 0;
};

class CGameState : public OIS::KeyListener,public OIS::MouseListener, public OgreBites::SdkTrayListener
{
public:
static void Create(CGameStateListener* parent, const Ogre::String name) {};

void destroy() { delete this; }

virtual void Enter() = 0;
virtual void Exit() = 0;
virtual bool Pause() { return true;}
virtual void Resume() {};
virtual void Update(double timeSinceLastFrame) = 0;

protected:
CGameState(){};

CGameState* FindByName(Ogre::String stateName) {return m_pListener->FindByName(stateName); }
void ChangeGameState(CGameState* state) { m_pListener->ChangeGameState(state); }
bool PushGameState(CGameState* state) { return m_pListener->PushGameState(state);}
void PopGameState() {m_pListener->PopGameState(); }
void Shutdown() { m_pListener->Shutdown(); }
void PopAllAndPushGameState(CGameState* state) { m_pListener->PopAllAndPushGameState(state); }

CGameStateListener* m_pListener;

Ogre::Camera* m_pCamera;
Ogre::SceneManager* m_pSceneMgr;
Ogre::FrameEvent m_FrameEvent;
};

// macro define
#define DECLARE_GAMESTATE_CLASS(T) \
static void Create(CGameStateListener* pListener, const Ogre::String name) \
{ \
T* newState = new T(); \
newState->m_pListener = pListener; \
pListener->ManageGameState(name, newState); \
} \

#endif //_ZH_GAMESTATE_H_

 

上面代碼中最后有一個宏定義,它的做用就是定義每個狀態,並把它自己注冊進狀態管理類里。這是為了讓你少寫一些代碼,不然你每定義一個狀態類就得寫一遍這個函數,有這個宏就方便多了。

 

可以看一下類圖:

GameStateManager.h

/********************************************************************
created: 2012/02/25
created: 25:2:2012 16:05
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\GameStateManager.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: GameStateManager
file ext: h
author: Star

purpose: Manage all the game states
********************************************************************
*/

#ifndef _ZH_GAMESTATEMANAGER_H_
#define _ZH_GAMESTATEMANAGER_H_

#pragma once
#include "GameState.h"

class CGameStateManager : public CGameStateListener
{
public:
typedef struct
{
Ogre::String name;
CGameState* state;
} SState_info;

CGameStateManager();
~CGameStateManager();

void ManageGameState(Ogre::String stateName, CGameState* state);

CGameState* FindByName(Ogre::String stateName);

void Start(CGameState* state);
void ChangeGameState(CGameState* state);
bool PushGameState(CGameState* state);
void PopGameState();
void PauseCurGameState();
void Shutdown();
void PopAllAndPushGameState(CGameState* state);

protected:
void Init(CGameState* state);

std::vector<CGameState*> m_ActiveStateStack;
std::vector<SState_info> m_States;
bool m_bShutdown;
};

#endif //_ZH_GAMESTATEMANAGER_H_

這個就是狀態管理類,這里邊的Start函數,就是程序消息循環的位置了。狀態的切換也都在這里邊發生。

這些函數的實現我就不復制,粘貼了,到時最后會發一個代碼鏈接。

 

有了這些狀態定義,我們現在就來試一下,先做一個MenuState。

MenuState.h

/********************************************************************
created: 2012/02/27
created: 27:2:2012 11:40
filename: E:\Ogre\Project\Ogre_Project\Game_Demo\MenuState.h
file path: E:\Ogre\Project\Ogre_Project\Game_Demo
file base: MenuState
file ext: h
author: Star

purpose: the menu of the game
********************************************************************
*/

#ifndef _ZH_MENUSTATE_H_
#define _ZH_MENUSTATE_H_

#pragma once

#include "GameState.h"

class CMenuState : public CGameState
{
public:
CMenuState();

DECLARE_GAMESTATE_CLASS(CMenuState)

void Enter();
void CreateScene();
void Exit();

bool keyPressed(const OIS::KeyEvent &evt);
bool keyReleased(const OIS::KeyEvent &evt);

bool mouseMoved( const OIS::MouseEvent &evt);
bool mousePressed( const OIS::MouseEvent &evt, OIS::MouseButtonID id );
bool mouseReleased( const OIS::MouseEvent &evt, OIS::MouseButtonID id );

void buttonHit(OgreBites::Button* button);

void Update(double timeSinceLastFrame);

private:
bool m_bQuit;

};

#endif //_ZH_MENUSTATE_H_


主要講一下Enter函數,這里邊就要創建一下菜單界面了,還有Camera和SceneManager的創建,用的是OGRE現在帶的SDKTray。然后也可以創建場景,這樣就會有比較動感的開始菜單界面了等。

void CMenuState::Enter()
{
Ogre::FontManager::getSingleton().getByName("SdkTrays/Caption")->load();
COgreFramework::getSingletonPtr()->m_pLog->logMessage("Entering MenuState.h.");

m_pSceneMgr = COgreFramework::getSingletonPtr()->m_pRoot->createSceneManager(ST_GENERIC, "MenuSceneMgr");
m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.7f, 0.7f, 0.7f));

m_pCamera = m_pSceneMgr->createCamera("MenuCam");
m_pCamera->setPosition(Vector3(0, 25, -50));
m_pCamera->lookAt(Vector3(0, 0, 0));
m_pCamera->setNearClipDistance(1);

m_pCamera->setAspectRatio(Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualWidth())/
Real(COgreFramework::getSingletonPtr()->m_pViewport->getActualHeight()));

COgreFramework::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);

COgreFramework::getSingletonPtr()->m_pTrayMgr->destroyAllWidgets();
COgreFramework::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
COgreFramework::getSingletonPtr()->m_pTrayMgr->showLogo(OgreBites::TL_BOTTOMRIGHT);
COgreFramework::getSingletonPtr()->m_pTrayMgr->showCursor();
COgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "EnterBtn", "Enter GameState", 250);
COgreFramework::getSingletonPtr()->m_pTrayMgr->createButton(OgreBites::TL_CENTER, "ExitBtn", "Exit OgreFramework", 250);
COgreFramework::getSingletonPtr()->m_pTrayMgr->createLabel(OgreBites::TL_TOP, "MenuLbl","Menu mode", 250);

CreateScene();
}

 

這邊有一個注意項:

如果沒有這句的話

 Ogre::FontManager::getSingleton().getByName("SdkTrays/Caption")->load();

我這邊頂上的那個Label里是不顯示文字的,在他的論壇里找到這么一個解決方案。


最后的效果截圖:

 

通過這樣的框架就可以搭建自己的游戲了,只要繼承GameState,實現自己的場景繪制和UI,就好了。期待你的游戲的產生。

資源下載:

http://download.csdn.net/detail/sunstar1989/4094433


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM