【Cocos2d-x游戏开发】Cocos2d-x中的数据存储技术

  一、引言

  数据存储和网络功能可以说是一款游戏中必不可少的功能,如果一款游戏不能保存进度那么它的可玩性必然大打折扣(试想一下,玩家辛辛苦苦玩了一整天的游戏,结果退出时告诉人家不能保存关卡信息,你明天还得从头来再玩一遍。那玩家一定会掏出准备已久的西瓜刀~)

  其实Cocos2d-x引擎早已为我们开发者封装好了多种数据存储的类或者方法,包括简单信息的存储,文件的读写,SQLite数据库和RAR格式的压缩文件的读取等等。(用心良苦啊!)其中大部分的存储功能被封装到了UserDefault类中。

  二、数据存储

  1.UserDefault类

  UserDefault 是一个小型的数据管理类。你可以通过这个类保存并获得基本类型值的数据。 例如:setBoolForKey("played", true) 将在数据库中添加一个值为 true 的布尔型数据。 它的 key 是 "player"。可以通过 getBoolForKey("player") 获取这个数据。

  UserDefault类提供了一些常用的方法用于读取和存储数据信息,如下表:

UserDefault类的常用方法
方法名 说              明
getBoolForKey 获取bool类型的键值对的值
getIntegerForKey 获取int类型的键值对的值
getFloatForKey 获取float类型的键值对的值
getDoubleForKey 获取double类型的键值对的值
getStringForKey 获取String类型的键值对的值
getDataForKey 获取二进制的键值对的值
setBoolForKey 存入bool类型的数据
setIntegerForKey 存入int类型的数据
setFloatForKey 存入float类型的数据
setDoubleForKey 存入double类型的数据
setStringForKey 存入String类型的数据
setDataForKey 存入二进制数据
flush 将内容保存到XML文件
getXMLFilePath 获取XML文件的保存路径
isXMLFileExist 判断一个XML文件是否存在

  具体的参数及详细的说明可以在Cocos2d-x的UserDefaultAPI文档中查询(吐槽一句Cocos2d-x的文档真够差劲的,相比之下Egret的文档好很多。)

  OK,下面我们写一个小例子,来看一下UserDefault这个类具体是怎么使用的,先上代码:

 1 bool HelloWorld::init()
 2 {
 3     if ( !Layer::init() )
 4     {
 5         return false;
 6     }
 7     auto* background = LayerColor::create(Color4B(255, 255, 255, 255));
 8     addChild(background);
    //创建一个菜单按钮
9 auto* readLabel = Label::create("read", "Arial", 56); 10 readLabel->setColor(Color3B(0, 0, 0)); 11 auto* pReadLabel = MenuItemLabel::create(readLabel, this, menu_selector(HelloWorld::readCallback)); 12 auto* buttonReadLabel = Menu::create(pReadLabel, NULL); 13 buttonReadLabel->setPosition(320, 260); 14 addChild(buttonReadLabel); 15 auto* saveLabel = Label::create("save", "Arial", 56); 16 saveLabel->setColor(Color3B(0, 0, 0)); 17 auto* pSaveLabel = MenuItemLabel::create(saveLabel, this, menu_selector(HelloWorld::saveCallback)); 18 auto* buttonSaveLabel = Menu::create(pSaveLabel, NULL); 19 buttonSaveLabel->setPosition(320, 100); 20 addChild(buttonSaveLabel); 21 UserDefault::sharedUserDefault()->setBoolForKey("isExisted",false); 22 return true; 23 } 24 void HelloWorld::readCallback(Ref* pSender) 25 { 26 CCLOG("============================================================"); 27 CCLOG("reading begin!");
    //根据isExisted的值来判断,是否数据被写入
28 if (UserDefault::sharedUserDefault()->getBoolForKey("isExisted")) 29 {
      //读取键值为Int的内容并输出
30 int intVar = UserDefault::sharedUserDefault()->getIntegerForKey("int"); 31 CCLOG("the int is:%d", intVar);
      //读取键值为float的内容并输出      
32 float floatVar = UserDefault::sharedUserDefault()->getFloatForKey("float"); 33 CCLOG("the float is:%f", floatVar);
      //读取键值为string的内容并输出
34 std::string str = UserDefault::sharedUserDefault()->getStringForKey("string"); 35 CCLOG("the string is:%s", str); 36 }
    //如果isExisted的键值为false的话,说明信息没有被保存,不可用
37 else 38 { 39 CCLOG("not exist!"); 40 } 41 CCLOG("============================================================"); 42 } 43 void HelloWorld::saveCallback(Ref* pSender) 44 { 45 CCLOG("============================================================"); 46 CCLOG("save begin!"); 47 UserDefault::sharedUserDefault()->setIntegerForKey("int", 999); 48 UserDefault::sharedUserDefault()->setFloatForKey("float", 3.1415926); 49 UserDefault::sharedUserDefault()->setStringForKey("string", "this is a string!"); 50 UserDefault::sharedUserDefault()->setBoolForKey("isExisted", true); 51 CCLOG("saved file path is %s", UserDefault::sharedUserDefault()->getXMLFilePath()); 52 CCLOG("============================================================"); 53 }

  程序运行起来以后可以看到read和save两个按钮,点击他们可以看到在控制台打印出来的信息,如下图:

  

  可以看到,数据信息已经被成功的写入并且读取出来了,而且还打印了文件的存放路径。这种方式特别适合保存游戏进度和最高分、排行榜等内容比较少的数据。但是如果数据量比较大的时候就需要采取别的方式了,比如文件读写的方式。

  二、Cocos2dx中的文件读写

 1 bool HelloWorld::init()
 2 {
 3     if ( !Layer::init() )
 4     {
 5         return false;
 6     }
 7     // 创建一个菜单按钮,用于读取文件中的内容
 8     auto* background = LayerColor::create(Color4B(255, 255, 255, 255));
 9     addChild(background);
10     auto* readLabel = Label::create("read", "Arial", 56);
11     readLabel->setColor(Color3B(0, 0, 0));
12     auto* pReadLabel = MenuItemLabel::create(readLabel, this, menu_selector(HelloWorld::readCallback));
13     auto* buttonReadLabel = Menu::create(pReadLabel, NULL);
14     buttonReadLabel->setPosition(320, 260);
15     addChild(buttonReadLabel);
16     auto* saveLabel = Label::create("save", "Arial", 56);
17     saveLabel->setColor(Color3B(0, 0, 0));
18     auto* pSaveLabel = MenuItemLabel::create(saveLabel, this, menu_selector(HelloWorld::saveCallback));
19     auto* buttonSaveLabel = Menu::create(pSaveLabel, NULL);
20     buttonSaveLabel->setPosition(320, 100);
21     addChild(buttonSaveLabel);
22     return true;
23 }
24 void HelloWorld::readCallback(Ref* pSender)
25 {
26     CCLOG("============================================================");
27     std::string path = FileUtils::sharedFileUtils()->getWritablePath()+"test.txt";
28     // 输出文件路径
29     CCLOG("path = %s", path.c_str());
30     // 创建一个文件指针
31     FILE* file = fopen(path.c_str(), "r");
32     if (file) {
33         char* buf;  //要获取的字符串  
34         int len;    //获取的长度  
35         // 获取文件长度长度
36         fseek(file, 0, SEEK_END);   //移到尾部  
37         len = ftell(file);          //提取长度  
38         rewind(file);               //回归原位  
39         CCLOG("count the file content len = %d", len);
40         //分配buf空间  
41         buf = (char*)malloc(sizeof(char) * len + 1);
42         if (!buf) 
43         {
44             CCLOG("malloc space is not enough.");
45         } 
46         //读取进的buf,单位大小,长度,文件指针  
47         int rLen = fread(buf, sizeof(char), len, file);
48         buf[rLen] = '\0';
49         CCLOG("has read Length = %d", rLen);
50         CCLOG("has read content = %s", buf);
51         fclose(file);
52         free(buf);
53     }
54     else
55     {
56         CCLOG("open file error.");
57     }
58     CCLOG("============================================================");
59 }
60 void HelloWorld::saveCallback(Ref* pSender)
61 {
62     CCLOG("============================================================");
63     std::string path = CCFileUtils::sharedFileUtils()->getWritablePath() + "test.txt";
64     FILE* file = fopen(path.c_str(), "w");
65     if (file) 
66     {
67         char* pContent = "this is a word";
68         fputs(pContent, file);
69         CCLOG("save file succeed.");
70         fclose(file);
71     }
72     else
73     {
74         CCLOG("save file error.");
75     }
76     CCLOG("============================================================");
77 }

 程序运行调试图:

 

  Cocos2d-x中文件读写的方式和C++对文件的操作是一样的,先创建一个文件指针指向一个文件,然后打开这个文件,接着写入数据,最后关闭文件。以下是详细说明:

  File对象:文件对象,用于创建文件,操作文件。

  fopen:打开一个文件,可以根据参数的不同来决定文件的打开方式(比如 r,w,a等等)。

  fseek:移动文件指针,可以将指针指向文件中特定位置的字符。

  ftell:获取文件指针相对于文件开头的距离。

  malloc:为指针分配内存。

  fread:读取一个文件,需要输入缓冲区的地址,单位大小,长度和文件指针。

  更多详细的文件操作内容可以移步此篇博文

  其实在Cocos2d-x中还有利用比如csv,json等保存数据的方法,但由于篇幅限制,本篇博客中我们就不再探讨了,以后的博客中会详细的介绍json和csv的操作。

 

  本篇博客所有代码已经同步到Github:

  UserDefault类使用:https://github.com/XINCGer/Cocos2d-X_Tools/tree/master/Cocos2d-x_Demo/LocalDataSave

  文件读写操作:https://github.com/XINCGer/Cocos2d-X_Tools/tree/master/Cocos2d-x_Demo/FileSystemInCocos2dx

  下一篇博客,我们将学习Cocos2d-X中的弱联网技术。

 

作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/5744177.html 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!

posted @ 2016-08-07 11:33  马三小伙儿  阅读(6103)  评论(2编辑  收藏  举报