[读书笔记]<游戏引擎架构>|管理器的启动与终止
2016-11-28 01:03
477 查看
每个游戏都会包含一些底层支持系统, 例如资源管理器、日志系统、对象池、动画管理器、音乐/音效管理器等。这些管理器通常是一个单例类,如下面这段代码:
我所在的项目之前就是使用这种方式实现的。
然而,这种方式有个极大的弊端,就是不能控制其构造和析构的时间。假如A管理器依赖B管理器,而在B管理器创建之前A已经被调用,或者B管理器已经被析构,而A还存在, 很有可能导致严重问题。
事实上这个实现方式确实导致过我们游戏崩溃。
于是上述设计被改成如下方案:
即明确的为各单例管理器定义构造和析构的函数,替代简单的get,这样就可以按所需的明确次序调用各启动和终止函数。
书中提到了更优雅的方法是:启动时将这些管理器按所需次序启动并放入一个栈中,这样终止时,可以逐一把管理器弹出栈并调用终止函数。根据这个思路,我想到如下实现:
这种方式有个好处,在新增或者修改导致一些管理器的依赖顺序改变时,只需要修改Init函数中的启动顺序,则终止的顺序也会跟着改变。引擎开发者只需要关注管理器的启动顺序就好。
class ResourceManager { private: static ResourceManager* m_pInstance; public: static ResourceManager* get() { if(m_pInstance == nullptr) { m_pInstance = new ResourceManager(); } return m_pInstance; } };
我所在的项目之前就是使用这种方式实现的。
然而,这种方式有个极大的弊端,就是不能控制其构造和析构的时间。假如A管理器依赖B管理器,而在B管理器创建之前A已经被调用,或者B管理器已经被析构,而A还存在, 很有可能导致严重问题。
事实上这个实现方式确实导致过我们游戏崩溃。
于是上述设计被改成如下方案:
class ResourceManager { private: static ResourceManager* m_pInstance; public: static ResourceManager* get() { return m_pInstance; } static void createInstance() { m_pInstance = new ResourceManager(); } static void destoryInstance() { delete m_pInstance; } }; //其他管理器 ... // class GOW { static void Init() { ResourceManager::createInstance(); //其他管理器同上 ... // } static void UnInit() { ResourceManager::destoryInstance(); //其他管理器同上 ... // } };
即明确的为各单例管理器定义构造和析构的函数,替代简单的get,这样就可以按所需的明确次序调用各启动和终止函数。
书中提到了更优雅的方法是:启动时将这些管理器按所需次序启动并放入一个栈中,这样终止时,可以逐一把管理器弹出栈并调用终止函数。根据这个思路,我想到如下实现:
class IManager { static void startUp() = 0;//启动管理器 static void shutDown() = 0;//终止管理器 }; class ResourceManager: public IMananger { private: static ResourceManager* m_pInstance; ResourceManager() { //不做任何事 } ~ResourceManager() { //不做任何事 } public: static ResourceManager* get() { if(m_pInstance == nullptr) { m_pInstance = new ResourceManager(); } return m_pInstance; } static void startUp() override { //管理器的启动代码 } static void shutDown() override { //管理器的终止代码 } }; //其他管理器 ... // class GOW { private: static std::stack<IManager*> m_stkManager; //这里使用栈的原因是,一般先启动的管理器更为基础,所以要后终止 static void InitManager(IManager* pMananger) { pManager->startUp(); m_stkManager.push(pMananger); } public: static void Init() { InitManager(ResourceManager::get()); //其他管理器同上 ... // } static void UnInit() { while(!m_stkManager.empty()) { auto* pManager = m_stkManager.top(); m_stkManager.pop(); pManager->shutDown(); delete pManager; } } };
这种方式有个好处,在新增或者修改导致一些管理器的依赖顺序改变时,只需要修改Init函数中的启动顺序,则终止的顺序也会跟着改变。引擎开发者只需要关注管理器的启动顺序就好。
相关文章推荐
- [读书笔记]<游戏引擎架构>|仿射矩阵
- WEBGL 2D游戏引擎研发系列 第一章 <新的开始>
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏<一>
- <<App研发录:架构设计、Crash分析和竞品技术分析>>读书笔记
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏<一>2011-11-05 10:36
- <<面向模式的软件架构2-并发和联网对象模式>>读书笔记
- HTML5 2D游戏引擎研发系列 第四章 <Canvas技术篇-画布技术-基于手动切片动画>
- <大型网站技术架构>读书笔记
- 游戏集群架构<img src=javascript:alert("test")></img>
- 【技术讨论】从弹弹堂说起,如何用2D物理引擎编写一个游戏&lt;一&gt;2011-11-05 10:36
- WEBGL 2D游戏引擎研发系列 第一章 <新的开始>
- WEBGL 2D游戏引擎研发系列 第三章 <正交视口>
- 启动tomcat闪退,logs中提示元素类型 "Context" 必须由匹配的结束标记 "</Context>" 终止的解决方法
- WEBGL 2D游戏引擎研发系列 第五章 <操作显示对象>
- 游戏引擎的启动与终止【笔记】
- WEBGL 2D游戏引擎研发系列 第二章 <显示图片>
- HTML5 2D游戏引擎研发系列 第六章 <Canvas技术篇-画布技术-混色特效和粒子>
- <<Android.游戏开发入门](美)Mario.Zechner>>读书笔记-----OpenGL ES概览
- Nimbus<一>Storm系列(五)架构分析之Nimbus启动过程
- <考古笔记>hge游戏引擎(一)