【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)

时间:2022-08-31 10:56:14

本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010

一、对数据进行编解码

在上一期中,我们使用了CCUserDefault对游戏数据进行存储与读取,但是细心的我们肯定会想到,其游戏数据

存储文件是否安全呢?通过上一期对CCUserDefault的讲解,想必大家也很容易看出Cocos2D-X是以键值对进行存储

的,其存储方式其实是个xml文件,也就是说,游戏数据并不是那么安全。

这里我们一起来学习一个简单的对游戏数据进行加密的方法:使用Base64编码解码来实现。

对于Base64,由于篇幅限制,这里就不过多的介绍了,不是很熟悉的话可以自行查阅相关资料。

二、Base64C++代码

下面首先来看看Base64的C++版本的代码,我们将编码解码封装在一个BaseData类中,这个类的代码说明如下:

BaseData.h

#ifndef EDCodeTest_BaseData_h
#define EDCodeTest_BaseData_h
#include <string> std::string saveData( char const* , unsigned int len);
std::string parseData(std::string const& s); #endif

BaseData.cpp

#include "BaseData.h"

static const std::string dataChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; static inline bool isData(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
} std::string saveData( char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4]; while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; (i <4) ; i++)
ret += dataChars[char_array_4[i]];
i = 0;
}
} if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j < i + 1); j++)
ret += dataChars[char_array_4[j]]; while((i++ < 3))
ret += '='; }
return ret; } std::string parseData(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret; while (in_len-- && ( encoded_string[in_] != '=') && isData(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = dataChars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
} if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0; for (j = 0; j <4; j++)
char_array_4[j] = dataChars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
} return ret;
}

此类中我们封装了两个重要的函数saveData和parseData,它们分别对数据进行编码和解码。

<1> std::string saveData(char const * ,unsigned int len)

作用:对字符串数据进行编码。

参数1:需要编码的目标字符串。

参数2:目标字符串长度。

<2> std::string parseData(std::string const & s)

作用:对字符串数据进行解码。

参数:需要解码的目标字符串。

三、项目实例

1、首先新建Cocos2D-X项目,取名为“MyDataSave02”,然后在项目中加入之前的BaseData类,最后在

HelloWorldScene.cpp文件的init函数中添加如下所示代码。

bool HelloWorld::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init()); //需要存储的字符串
string sValue = "Yangyu";
//对存储的数据进行编码
string saveBaseString = saveData(sValue.c_str(), sValue.length());
//将得到编码后的数据进行存储
CCUserDefault::sharedUserDefault()->setStringForKey("Base", saveBaseString);
CCUserDefault::sharedUserDefault()->flush(); //从存储中获取编码的数据
string loadBaseString = CCUserDefault::sharedUserDefault()->getStringForKey("Base");
//对编码数据进行解码得到真实数据
string trueValue = parseData(loadBaseString); //---用以观察数据
CCLabelTTF* label = CCLabelTTF::create("", "Helvetica", 20);
label->setPosition(ccp(240,185));
addChild(label);
//编码之前的数据
string logStr = "Before Encoding:";
logStr+=sValue;
//编码之后的数据
logStr+=" After Encoding:";
logStr+=saveBaseString;
label->setString(logStr.c_str()); CCLabelTTF*label2 = CCLabelTTF::create("", "Helvetica", 20);
label2->setPosition(ccp(240,140));
addChild(label2);
//解码之前的数据
logStr = "Before Decode:";
logStr+=loadBaseString;
//解码之后的数据
logStr+=" After Decode:";
logStr+=trueValue;
label2->setString(logStr.c_str()); bRet = true;
} while (0); return bRet;
}

2、运行效果图

【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)

四、Base64编码解码工具

如果我们只是简单的将数据进行Base64编码,其实也是不安全的,对于稍微有些技术背景的人来说,对Base64解

码轻而易举!下图所示是我从网上随意使用了一个Base64解码工具,对刚编码的数据进行解码的例子。

【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)

在使用我提供的BaseData工具类时,我们需要在保存数据和读取数据时注意以下几点。

保存数据时:

<1> 当Base64对游戏数据进行编码后,不要着急进行存储,可以对编码后的字符串进行一些处理。例如在编码后的字符串中添加一

些无用字符、数字;或者在这个编码后的字符串进行位置调换操作等。

<2> 当对数据编码后的字符串进行处理后,在利用CCUserDefault进行保存。

读取数据时:

<1> 从存储文件中获取到数据后(已经做了处理的Base64编码字符串),首先对获取的数据进行反操作(按照存储

之前对编码字符串的操作进行反操作)。

<2> 反操作得到正确的Base64编码字符串后再进行Base64解码,以得到真实数据。

这里一来,除非破解者知道你做处理的过程,或者有你的源码,否则会很难破解你的数据。

源码下载地址

【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)的更多相关文章

  1. 【Cocos2d-X开发学习笔记】第29期:游戏中数据的存储(上)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010 一般游戏中都需要记录玩家数据,便于玩家下次登录时 ...

  2. 【Android开发学习笔记】【第八课】五大布局-下

    概念 五大布局上一篇文章已经介绍了 LinearLayout RelativeLayout 这一篇我们介绍剩下的三种布局 FrameLayout 五种布局中最佳单的一种布局.在这个布局在整个界面被当成 ...

  3. 基于&period;NET的CAD二次开发学习笔记二:AutoCAD &period;NET中的对象

    1.CAD对象:一个CAD文件(DWG文件)即对应一个数据库,数据库中的所有组成部分,看的见(包括点.多段线.文字.圆等)和看不见(图层.线型.颜色等)的都是对象,数据库本身也是一个对象. 直线.圆弧 ...

  4. Rest API 开发 学习笔记&lpar;转&rpar;

    Rest API 开发 学习笔记 概述 REST 从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表示方式.获得这些表徵致使这些应用程序转变了其状态.随着 ...

  5. Chrome扩展&comma;应用开发学习笔记之2---恶搞百度一下

    Chrome扩展,应用开发学习笔记之2 恶搞百度一下 前面我们介绍了一个最简单的chrome扩展时钟,如今我来介绍一下一个恶搞百度一下的chrome扩展程序. 前面说过,manifest.json文件 ...

  6. 【前端】移动端Web开发学习笔记【2】 &amp&semi; flex布局

    上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...

  7. 【前端】移动端Web开发学习笔记【1】

    下一篇:移动端Web开发学习笔记[2] Part 1: 两篇重要的博客 有两篇翻译过来的博客值得一看: 两个viewport的故事(第一部分) 两个viewport的故事(第二部分) 这两篇博客探讨了 ...

  8. 驱动开发学习笔记&period; 0&period;07 Uboot链接地址 加载地址 和 链接脚本地址

    驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...

  9. android开发学习笔记000

    使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...

随机推荐

  1. java中&period;equals和&equals;&equals;的区别?

    Java中的equals是十分重要的,和= =要区别开来,孙卫琴的JAVA面向对象编程一书对这个做了阐述,现在小结其主要内容,而且要将 = =和 equals列为重要的对比概念来学习 1.声明格式   ...

  2. Struts2中的session、request、respsonse获取方法

    个人对于struts有一种复杂的心情,平心而论,struts2是个人最早接触到的的框架,在学校的时候就已经开始学习了,大四毕业设计,无疑用的还是struct,那时候SSH还是很流行的,后来出来实习,直 ...

  3. Linux系统编程(28)——线程间同步

    多个线程同时访问共享数据时可能会冲突,这跟前面讲信号时所说的可重入性是同样的问题.比如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成: 从内存读变量值到寄存器 寄存器的值加1 将寄 ...

  4. &lbrack;Dev Blog&rsqb; KCV插件 —— Provissy Tools 。

    承蒙各位支持! 正式版已推出,请前往http://tieba.baidu.com/p/3398574166 或者前往:http://provissy.com/?p=7 请不要在这里回复,我无法保证回复 ...

  5. Android 手机应用开发经验 之 通过Socket&lpar;TCP&sol;IP&rpar;与PC通讯

    Android 是一个开源的手机操作系统平台,已经被非常多的开发者视作未来最有潜力的智能手机操作系统.而且,在很短的时间内就在Android Market上出现大量的第三方应用程序,供用户下载与使用, ...

  6. mybatics问题记录

    一.Parameter 'name' not found. Available parameters are [0, 1, param1, param2]. 传入多个值时,mybatis会自动将这些值 ...

  7. UITabBarItem title 和self&period;title设置不同的标题

    self.navigationItem.title = @"my title"; //sets navigation bar title. self.tabBarItem.titl ...

  8. RPC 简单小试

    由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器 ...

  9. 调试maven源代码

    下载源代码,导入idea 运行MavenCli ,设置vm参数 -Dclassworlds.conf=/Users/fsq/Downloads/apache-maven-3.6.2.0/bin/m2. ...

  10. appium&plus;python自动化33-解锁九宫格(TouchAction)

    TouchAction 1.源码可以在这个路径找到:Lib\site-packages\appium\webdriver\common\touch_action.py class TouchActio ...