前言:

  一般游戏需要在手机上记录一些简单的信息,用来保存游戏的进度,玩家的分数等。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 关于路径

    在eclipse中如果没有指名文件的路径的话,系统默认是与src同一级别的目录路径!

  2. 学号:201521123116 《java程序设计》第四周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 注释的应用使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看.(截图)答:注释的插入:注释以/开始,以/结束类注释/**.... ...

  3. 201521123050《Java程序设计》第2周学习总结

    本周学习总结 (1)掌握各种数据类型的使用 基本类型 整数类型(byte,short,int,long,char) 浮点类型(float,double) boolean类型(true, false) ...

  4. list,set,map总结

    学习了集合,脑子里list,set,map之间的关系有混乱,在这里整理一下.有兴趣的朋友可以看下. 先看下 list,set,map各自的特点

  5. Linux如何设置dns

    首先打开dns设置文档 空的dns文档如图所示 键入图片中的文本保存即可设置了自己的dns 保存后推出即可.

  6. evak购物车-课程设计(201521123034陈凯欣)

    1.团队课程设计博客链接 https://i.cnblogs.com/EditPosts.aspx?postid=7047127 2.个人负责模块或任务说明 1.Java 编写商品类Goods,商品属 ...

  7. 201521123118《java与程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  8. 使用electron将应用程序加入到系统托盘

    博主电脑

  9. [01] Servlet是什么

    1.Servlet是什么 Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序.其主要功能在于交互式地浏览和修改数据,生成动态Web内容. 1.1 ...

  10. 【】小技巧】CSS文字两端对齐

    需求如下,红框所在的文字有四个字的.三个字的.两个字的,如果不两端对齐可以选择居中对齐,或者右对齐.但是如果要像下面这样两端对齐呢? 我相信以前很多人都这么干过:两个字中间使用 来隔开达到四个字的宽度 ...