cocos2dx - Sqlite简单封装使用
前言:
一般游戏需要在手机上记录一些简单的信息,用来保存游戏的进度,玩家的分数等。SQLite作为轻量级、跨平台的关系型数据库,相当适合用于游戏数据的存储。
由于没有加密,有安全性问题,数据上还需要自己做些加密验证等。
封装效果
为了达到简单易用的效果,封装后接口大致如下。通过仅通过调用GetData和SetData来获取数据及存储数据。
class CDataMgr
{
public:
static CDataMgr* getInstance(); static void destroyInstance(); const SSqlData& GetData(enDataType nType){ return m_mKeyValue[nType]; } void SetData(enDataType nType, SSqlData& data);
private:
void GetSqlData(enSqlTableType nSqlType, std::vector<enDataType>& vDataType); void SaveSqlTable(enSqlTableType nSqlType); void OpenSql(enSqlTableType nType); // 打开数据库操作 void CloseSql(); // 关闭数据库操作 CDataMgr();
~CDataMgr(); std::map<enDataType, SSqlData> m_mKeyValue; // 程序当前的值
sqlite3 * m_pSqlData; // 数据库指针 };
辅助数据结构
Get及Set得到的数据需要知道类型且可以得到正常的值,同时还需要设置在sqlite中字段名字等,因此需要几个辅助的结构体来存储数据类型等。如下:
// 数据枚举
enum class enDataType
{
SOUND, // 声音数据 0x01 音乐 0x02 音效 (1:开启,0:关闭)
PLAYERID, // 上次GAMECENTER玩家数据
ISGUIDED, // 是否已经引导过
LASTTIME, // 上次时间 PLAYER_INDEX, // 每个的索引
MONEY, // 金币
RECORD, // 记录
}; // Sqlite表格类型
enum class enSqlTableType
{
DEFAULT, // 默认数据存储 声音等
PLAYER, // 玩家数据存储 金币
}; // 存储数据类型
enum class enSqlDataType
{
NONE, // 没有数据
INT, // int类型
LONG, // long类型
BOOL, // bool 类型
STRING, // string 类型
}; // 数据结构体
struct SSqlData
{
public:
SSqlData()
{
memset(&udata, , sizeof(udata));
}
SSqlData(enSqlTableType ntable, enSqlDataType ntype, std::string name)
:nSqlTableType(ntable), nSqlDataType(ntype), sSqlDataName(name)
{
memset(&udata, , sizeof(udata));
} // 实际数据
union UData
{
int _intData;
long _longData;
bool _boolData;
};
UData udata;
std::string _strData; enSqlTableType nSqlTableType; // 数据表格
enSqlDataType nSqlDataType; // 数据库中数据类型
std::string sSqlDataName; // 数据库中名字
};
简单说明:
1、SSqlData是实际设置获取的数据,里面包含有Sqlite的字段名字,数据类型及实际保存数据等。
2、enSqlDataType 是数据存储类型的枚举。
3、enSqlTableType 是数据表格的枚举类型,一般游戏至少有2张表格,分别用来存储每个玩家数据(分数)及所有玩家共同的数据(声音)。
4、enDataType 是列举了所有的游戏存储值的枚举,用来索引SSqlData的,游戏通过enDataType 来获取SSqlData。
数据初始化描述
游戏初始化时在DataMgr的构造函数中需要对所有的枚举值进行描述,设置所属表格及字段类型,字段名等。同时还需要从Sqlite取出默认的数据,如下:
CDataMgr::CDataMgr() :m_pSqlData()
{
// 初始化key-value
m_mKeyValue[enDataType::SOUND] = SSqlData(enSqlTableType::DEFAULT, enSqlDataType::INT, "sound");
m_mKeyValue[enDataType::PLAYERID] = SSqlData(enSqlTableType::DEFAULT, enSqlDataType::STRING, "playerId");
m_mKeyValue[enDataType::ISGUIDED] = SSqlData(enSqlTableType::DEFAULT, enSqlDataType::BOOL, "isGuided");
m_mKeyValue[enDataType::LASTTIME] = SSqlData(enSqlTableType::DEFAULT, enSqlDataType::LONG, "lastTime"); m_mKeyValue[enDataType::MONEY] = SSqlData(enSqlTableType::PLAYER, enSqlDataType::LONG, "money");
m_mKeyValue[enDataType::RECORD] = SSqlData(enSqlTableType::PLAYER, enSqlDataType::LONG, "record");
m_mKeyValue[enDataType::PLAYER_INDEX] = SSqlData(enSqlTableType::PLAYER, enSqlDataType::STRING, "playerId"); std::vector<enDataType> vDataType;
vDataType.push_back(enDataType::PLAYERID);
vDataType.push_back(enDataType::SOUND);
vDataType.push_back(enDataType::LASTTIME);
vDataType.push_back(enDataType::ISGUIDED);
GetSqlData(enSqlTableType::DEFAULT, vDataType); // 获取数据库记录 vDataType.clear();
vDataType.push_back(enDataType::MONEY);
vDataType.push_back(enDataType::RECORD);
GetSqlData(enSqlTableType::PLAYER, vDataType); // 获取数据库记录
}
数据存储
为了节省效率,在实际SetData及GetData并不会从Sqlite中存取,而是从缓存的 m_mKeyValue 中取值设置。然而当玩家角色发生变化及游戏结束就必须及时对玩家数据进行存储。
因此在析构函数及SetData中有如下操作:
CDataMgr::~CDataMgr()
{
SaveSqlTable(enSqlTableType::DEFAULT);
SaveSqlTable(enSqlTableType::PLAYER);
} void CDataMgr::SetData(enDataType nType, SSqlData& data)
{
// 玩家角色变化更新玩家数据
if (enDataType::PLAYERID == nType)
{
SaveSqlTable(enSqlTableType::PLAYER);
m_mKeyValue[nType] = data;
std::vector<enDataType> vDataType;
vDataType.push_back(enDataType::MONEY);
vDataType.push_back(enDataType::RECORD);
GetSqlData(enSqlTableType::PLAYER, vDataType);
}
else
{
m_mKeyValue[nType] = data;
}
}
测试数据:
SSqlData guid_data = CDataMgr::getInstance()->GetData(enDataType::ISGUIDED);
SSqlData last_data = CDataMgr::getInstance()->GetData(enDataType::LASTTIME);
SSqlData player_data = CDataMgr::getInstance()->GetData(enDataType::PLAYERID);
SSqlData record_data = CDataMgr::getInstance()->GetData(enDataType::RECORD); CCLOG("guid_data:%d", guid_data.udata._boolData ? : );
CCLOG("lasttime:%ld", last_data.udata._longData);
CCLOG("player:%s", player_data._strData.c_str());
CCLOG("record:%ld", record_data.udata._longData); guid_data.udata._boolData = true;
player_data._strData = "xxxxxxxxxxzzzzzzzzzz___1";
record_data.udata._longData = ; CDataMgr::getInstance()->SetData(enDataType::ISGUIDED, guid_data); // 通用引导数据变化
CDataMgr::getInstance()->SetData(enDataType::PLAYERID, player_data); // 登录玩家变化
CDataMgr::getInstance()->SetData(enDataType::RECORD, record_data); // 玩家记录变化 record_data = CDataMgr::getInstance()->GetData(enDataType::RECORD);
CCLOG("record__1 :%ld", record_data.udata._longData); player_data._strData = "xxxxxxxxxxzzzzzzzzzz_____2";
CDataMgr::getInstance()->SetData(enDataType::PLAYERID, player_data); // 登录玩家变化
record_data = CDataMgr::getInstance()->GetData(enDataType::RECORD);
CCLOG("record__2 :%ld", record_data.udata._longData);
结果如下图:

当然,也可以通过sqliteadmin之类的软件直接打开db文件查看数据,因为没加密~~~~~~~~~~
完整代码地址:https://github.com/mydishes/cocos2dx-Ex/tree/master/SqliteMgr
cocos2dx - Sqlite简单封装使用的更多相关文章
- iOS sqlite 增删改查 简单封装(基于 FMDB)
/** * 对 sqlite 的使用进行简单封装,仅涉及简单的单表 增删改查 * * 基于 FMDB * * 操作基于 model ,数据库表字段与 model 属性一一对应,对 model 整 ...
- FMDB简单封装和使用
工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...
- iOS开发数据库篇—SQLite简单介绍
iOS开发数据库篇—SQLite简单介绍 一.离线缓存 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等. 说明:离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式 (1 ...
- 【转】 iOS开发数据库篇—SQLite简单介绍
开始学SQLite啦, 原文: http://www.cnblogs.com/wendingding/p/3868893.html iOS开发数据库篇—SQLite简单介绍 一.离线缓存 在项目开发中 ...
- SQLite简单介绍
一.离线缓存 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等. 说明:离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式 (1)归档:NSCodeing.NSKeyed ...
- .net core 中简单封装Dapper.Extensions 并使用sqlsuger自动生成实体类
引言 由公司需要使用dapper 同时支持多数据库 又需要支持实体类 又需要支持sql 还需要支持事务 所以采用了 dapper + dapperExtensions 并配套 生成实体类小工具的方 ...
- Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...
- Android--Retrofit+RxJava的简单封装(三)
1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...
- okhttp3 get post 简单封装
最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...
随机推荐
- cobbler部署安装CentOS6.8
Linux运维:cobbler : 矮哥linux运维群:93324526 学习cobbler的话,必须先搞懂kickstart,原理不是,不懂如何排错. kickstart部署请点击这里 1. Co ...
- Web前端和后端之区分,以及…
原文地址:Web前端和后端之区分,以及面临的挑战[转]作者:joyostyle 在我们实际的开发过程中,我们当前这样定位前端.后端开发人员. 1)前端开发人员:精通JS,能熟练应用JQuery,懂CS ...
- 201521123084 《Java程序设计》第5周学习总结
第5周-继承.多态.抽象类与接口 1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 1. 代码阅读:Child压缩包内源代码 1.1 com.parent包中C ...
- SNS团队第五次站立会议(2017.04.26)
一.当天站立式会议照片 本次会议主要内容:汇报工作进度,根据完成情况调整进度 二.每个人的工作 成员 今天已完成的工作 明天计划完成的工作 罗于婕 完善数据库文件 根据需求完善数据库文件 龚晓婷 编写 ...
- 201521123074 《Java程序设计》第7周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. (嗯..都画了那么久的导图,还是用导图归纳吧~) 2. 书面作业 ArrayList代码分析 1.1 解释ArrayList ...
- 201521123012 《Java程序设计》第六周学习总结
##1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. -注1:关键词与内容不求多,但概念之间的联系要清晰,内 ...
- 201521123062《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 多态定义:同种形态不同定义 类注释格式 继承,共同行为及属性 在instanceof检查过后 ...
- 201521123111《Java程序设计》第10周学习总结
1. 本章学习总结 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容 线程不是程序 线程必须在程序对应的进程中运行 一个进程中可以同时执行多个线程,这些线程可以完成不同的功能. 2. 书面 ...
- python日记_01 python实现6个人围成一圈,扔到第三个人出局,循环扔的问题。
#!/usr/bin/python shoplist=['mango','apple','carrot','banana','oracle','python'] length = len(shopli ...
- Day-18: 电子邮件
---恢复内容开始--- 假设要从**@163.com发送邮件到**@sina.com,会经过下面几个过程: 首先,你得使用邮件代理软件(也就是MUA:Mail User Agent),例如Outlo ...