游戏开发中的数据池问题和改进
来源:互联网 发布:通达信 引用贝格数据 编辑:程序博客网 时间:2024/06/05 09:49
之前开发游戏的时候,为了能够在任意地方都能访问到数据,一般的做法是建立一个数据池,然后把想要的数据全部放到数据池类中。数据池的写法一般是建一个名为DataPool的单例类,通常情况下对单例的实现一般是这样的
DataPool.h
#pragma onceclass DataPool{public: static DataPool* getInstance();};DataPool.cpp
#include <stdio.h>#include "DataPool.h"DataPool* g_instance = NULL;DataPool* DataPool::getInstance(){ if(NULL == g_instance){g_instance = new DataPool(); } return g_instance;}
为了方便演示数据池的工作方式,以下用游戏中常会涉及到用户账户信息和登录信息进行举例。通常情况下会建立两个类,这边暂时定为AccountInfo和LoginInfo。简单实现一下,类似下面:
用户信息类AccountInfo
AccountInfo.h
#pragma onceclass AccountInfo{public: AccountInfo(void); ~AccountInfo(void);};
AccountInfo.cpp
#include "AccountInfo.h"AccountInfo::AccountInfo(void){} AccountInfo::~AccountInfo(void){}登录信息类LoginInfo
LoginInfo.h
#pragma onceclass LoginInfo{public: LoginInfo(void); ~LoginInfo(void);};LoginInfo.cpp
#include "LoginInfo.h"LoginInfo::LoginInfo(void){}LoginInfo::~LoginInfo(void){}
既然这两个类建好了,那么下一步就是把它们丢到DataPool中,所以DataPool的代码也相应的更改
#pragma once#include "AccountInfo.h"#include "LoginInfo.h"class DataPool{public: static DataPool* getInstance();public: AccountInfo m_AccountInfo; LoginInfom_LoginInfo;};这边说的丢到DataPool中,其实就是把这两个类的实例作为DataPool的成员变量,并且把访问方式定位public,以后要访问的时候一般是
DataPool* pool = DataPool::getInstance();AccountInfo& account =pool->m_AccountInfo;LoginInfo& login = pool->m_LoginInfo;
也就是说所有的数据都要通过DataPool的单例访问,这样AccountInfo和LoginInfo作为DataPool的成员变量,也就拥有了单例的性质。同时也不用去管AccountInfo和LoginInfo的内存释放,因为他们的是以栈上对象的方式来声明的,其生命周期是随着DataPool的单例来管控的。DataPool什么时候释放,它们也跟着什么时候释放。
当然这样做法问题也是非常多的,比方说如果一个不小心把引用符号&去掉了,那么数据就会被拷贝一份。想象一下下面的写法:
LoginInfo login = pool->m_LoginInfo;//这边LoginInfo不是声明为LoginInfo&方式的,所以LoginInfo的数据就被拷贝
还有一个更让人头疼的问题是,由于把所有的数据都丢到DataPool中,那么相应的也得把这些数据类的头文件也包含到DataPool的头文件中,像上面的
#pragma once//看到了没,需要这两个头文件#include "AccountInfo.h"#include "LoginInfo.h"class DataPool{public: static DataPool* getInstance();public: AccountInfo m_AccountInfo; LoginInfo m_LoginInfo;};包含头文件本身没什么问题。问题是DataPool在开发过程中会被很多人修改,一般会有3到5个人在改它。而游戏中基本上每个业务逻辑类都要用到它,这样就造成了一个问题,DataPool随便一修改,相应的会有上百个文件也一起被编译。在没用联合编译工具的情况下,最可观的等待编译的时间是半个小时吧。
这些都是以前用在游戏开发的实现方案,一般是谁用谁苦逼。为此,需要对其进行改进。改进的技巧是用到了类成员模板函数以及typeid这个运行时运算符。
typeid这个运算符能够根据类型来返回类型的名称,举个例子
const char* name = typeid(AccountInfo).name();printf(name);//输出结果将是class AccountInfoname = typeid(LoginInfo).name();printf(name);//输出结果将是class LoginInfo接着看看DataPool改进后的样子
#pragma once#include <stdio.h>#include <typeinfo>#include <map>#include <string>using namespace std;class DataPool{public:static DataPool* getInstance();public:template<class T> T* get(){const char* name = typeid(T).name();std::map<std::string, void*>::iterator target = m_mapInstance.find(name);if(target != m_mapInstance.end()){return (T*)target->second;}else{T* instance = new T();m_mapInstance.insert(make_pair(name, instance));return instance;}return NULL;}protected:std::map<std::string, void*> m_mapInstance;};它的用法是
DataPool* pool = DataPool::getInstance();LoginInfo* info = pool->get<LoginInfo>();LoginInfo* info2 = pool->get<LoginInfo>();AccountInfo* account = pool->get<AccountInfo>();
在上面例子中info和info2这两个指针所指的对象是一样的,因为DataPool中对相同类型的数据进行了缓存。这样就可以在不改动DataPool的情况下来全局访问自己想要的数据,只要你通过get这个类成员模板函数。
现在看看get()模板函数的实现,这个函数的用途就是根据模板参数T以及typeid来取得该模板参数的类型名称
const char* name = typeid(T).name();//正如前面对typeid讲解的那样,这边将根据T的类型来返回T所对应的类型名称然后再在map中寻找之前这个模板参数的是否有缓存过,有的话直接用之前的实例。也就是这段代码
std::map<std::string, void*>::iterator target = m_mapInstance.find(name);if(target != m_mapInstance.end()){return (T*)target->second;}如果没有的,那么就创建一个实例,然后把它加入到map中
else{ T* instance = new T(); m_mapInstance.insert(make_pair(name, instance));//map的key为类型名称,value为分配出来的实例。 return instance;}通过以上改进之后,DataPool就不在依赖于特定数据的头文件了,同时也让DataPool固定下来,不会有大改动。自此,改进完成,有需要的各位可以试试。
- 游戏开发中的数据池问题和改进
- cocos2dx游戏开发中的问题
- Unity3D游戏开发中的数据存储
- 游戏中的AI算法总结与改进
- Android游戏——贪吃蛇开发实录(改进后的源码和详解)
- Android游戏——贪吃蛇开发实录(改进后的源码和详解)
- C# Unity游戏开发——Excel中的数据是如何到游戏中的
- 游戏中的数据存储
- java网络开发中的数据转换问题
- J2ME 2D游戏开发中的图形旋转问题
- 巧用原型继承解决游戏开发中的鼠标问题
- 也谈智能手机游戏开发中的分辨率自适应问题
- 利用双缓冲解决游戏开发中的屏幕闪烁问题
- TimeWalker游戏开发过程中的问题,经验与反思
- 游戏开发中的问题-----摘自《大型多人在线游戏开发》
- Unity游戏开发中的对象池
- 游戏开发中的数据结构
- 游戏开发中的坐标系
- 内部Handler类引起内存泄露
- Linux设备驱动实现自动创建设备节点
- Handler学习
- 黑马程序员--【经验分享】云7的0基础入学专科生,一样高薪就业!
- C++一些知识难点
- 游戏开发中的数据池问题和改进
- Android Service 极简总结
- 黑马程序员--三期已毕业学员诚致黑马的一封感谢信!
- 设计模式--原型模式
- 改变计算技术的伟大算法
- 黑马程序员--7期美女发来的感谢信,超级卡哇伊,快来围观啊。
- handler机制的原理
- Jquery UI的datepicker插件使用方法
- 关于SEO的相关知识