• 用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

  • 相关阅读:
    Canvas文字的渲染--进阶
    RK 调试笔记.
    Java Basic
    Android Basics
    RK Android5.1 亮度条、ContentObserver内容观察者模式
    Android 检测外接USB设备、读取GPIO节点
    RK Android7.1 音频播放 Standby
    latch的产生
    git cherry-pick 将其它分支的提交应用到当前分支
    git stash '储藏'当前工作状态
  • 原文地址:https://www.cnblogs.com/gameprogram/p/2370208.html
Copyright © 2020-2023  润新知