zoukankan      html  css  js  c++  java
  • cocos2dx

    前言:

      一般游戏需要在手机上记录一些简单的信息,用来保存游戏的进度,玩家的分数等。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, 0, sizeof(udata));
        }
        SSqlData(enSqlTableType ntable, enSqlDataType ntype, std::string name)
            :nSqlTableType(ntable), nSqlDataType(ntype), sSqlDataName(name)
        {
            memset(&udata, 0, 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(0)
    {
        // 初始化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 ? 1 : 0);
        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 = 100;
    
        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

  • 相关阅读:
    PHP sessions that have already been started
    DOM对象和JQuery对象的区别
    iOS在支持arc的工程中,导入不支持arc的第三方的插件
    Android下利用RadioGroup和RadioButton实现Tabbar的效果
    iOS7.1以后企业应用发布需要HTTPS协议,解决步骤
    Scrapy基础(四)————Scrapy的使用Pycharm进行Debuge设置
    Scrapy基础(三) ------xpath基础
    Scrapy基础(二)————Scrapy的安装和目录结构
    python基础一 ------Python 的编码
    Scrapy基础(一) ------学习Scrapy之前所要了解的
  • 原文地址:https://www.cnblogs.com/stratrail/p/5170801.html
Copyright © 2011-2022 走看看