前言:

  一般游戏需要在手机上记录一些简单的信息,用来保存游戏的进度,玩家的分数等。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简单封装使用的更多相关文章

  1. iOS sqlite 增删改查 简单封装(基于 FMDB)

    /** *  对 sqlite 的使用进行简单封装,仅涉及简单的单表 增删改查 * *  基于 FMDB * *  操作基于 model ,数据库表字段与 model 属性一一对应,对 model 整 ...

  2. FMDB简单封装和使用

    工具:火狐浏览器+SQLite Manager插件 ; Xcode; FMDB库; 效果: 项目地址: https://github.com/sven713/PackFMDB 主要参考这两篇博客: 1 ...

  3. iOS开发数据库篇—SQLite简单介绍

    iOS开发数据库篇—SQLite简单介绍 一.离线缓存 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等. 说明:离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式 (1 ...

  4. 【转】 iOS开发数据库篇—SQLite简单介绍

    开始学SQLite啦, 原文: http://www.cnblogs.com/wendingding/p/3868893.html iOS开发数据库篇—SQLite简单介绍 一.离线缓存 在项目开发中 ...

  5. SQLite简单介绍

    一.离线缓存 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等. 说明:离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式 (1)归档:NSCodeing.NSKeyed ...

  6. .net core 中简单封装Dapper.Extensions 并使用sqlsuger自动生成实体类

    引言 由公司需要使用dapper  同时支持多数据库 又需要支持实体类 又需要支持sql 还需要支持事务 所以采用了 dapper + dapperExtensions  并配套 生成实体类小工具的方 ...

  7. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池

    前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...

  8. Android--Retrofit+RxJava的简单封装(三)

    1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下 先创建一个HttpMethods类,将Ret ...

  9. okhttp3 get post 简单封装

    最近打算在新项目中使用 okhttp3, 简单封装了一下异步 get post 因为 CallBack 也是在子线程中执行,所以用到了 Handler public class MyOkHttpCli ...

随机推荐

  1. java课程设计——博客作业教学数据分析系统(201521123083 戴志斌)

    目录 一.团队课程设计博客链接 二.个人负责模块或任务说明 三.自己的代码提交记录截图 四.自己负责模块或任务详细说明 五.课程设计感想 (题外话,终于可以用markdown建目录) 一.团队课程设计 ...

  2. 201521044091 《java程序设计》第八周学习总结

    本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容.1.2 选做:收集你认为有用的代码片段 书面作业 本次作业题集集合 List中指定元素的删除(题目4-1)1.1 实验 ...

  3. 201521123024《Java程序设计》第7周学习总结

    1. 本周学习总结 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 public boolean contains(Object o) { re ...

  4. 201521123056 《Java程序设计》第1周学习总结

    1. 本周学习总结 java语言结构简单,但功能齐全,同时能够在不同系统平台上编译,但编译的前提是系统要有安装JVM(即java虚拟机),JVM是java实现跨平台的最核心部分.本周还学习了JDK.J ...

  5. 201521123110 java课程设计

    一.需求分析 功能要求:计算机产生随机数,猜中即胜,猜不中,提示是大了还是小了,继续猜,直至猜到,给出所用时间和评语.保留用户测试成绩,做出成绩排行榜.排行榜存放到文件中. 二.本组课题及本人任务 • ...

  6. 从java的开始,java概述,java配置环境变量

    一.java开发入门 java 概述   Java划分为三个技术平台:JavaSE(标准版,含Java基础类库),JavaEE(企业版,技术平台),JavaME(小型版,小型产品.嵌入式设备) Jav ...

  7. Python爬虫1-----------placekitten 入门

    常用的urllib库有三个类:request,parse,error,request主要完成对url的请求,如proxy,opener,urlopen,parse主要完成对html的解析,error负 ...

  8. IDEA运行编译后配置文件无法找到,或配置文件修改后无效的问题

    1.触发事件 今天正好在学习log4j,为了测试其配置文件log4j.properties中的各种配置,进行了频繁修改和程序启动以确认效果,因为是使用的IDEA建立的Web项目,接着问题就来了,配置文 ...

  9. C# 反射结构体struct的一个坑

    今天代码用到了反射赋值,代码是这样写的: var objtype = obj.GetType(); var Fieldinfo = objtype.GetField("I64"); ...

  10. 实现一个简单的虚拟DOM

    现在的流行框架,无论React还是Vue,都采用虚拟DOM. 好处就是,当我们数据变化时,无需像Backbone那样整体重新渲染,而是局部刷新变化部分,如下组件模版: <ul class=&qu ...