由于我要制作游戏的排行榜,在制作过程中遇到了不少的问题,一开始是不会把这个场景里面得到的数据传递到另一个页面,后来运用了UserDefault传值成功之后存入数组之中成功实现了排行榜以及排序的功能。然而却发现一个致命的bug,每一次关闭游戏打开之后排行榜里面的数据就被清空了,具体原因在下面再阐述。然后我就搜索了很多资料,查找了很多方法,发现不是版本不适合,就是没有办法实现我的功能。最后通过了tinyxml2 这个已经被集成在cocos2dx 3.6版本中的这个功能实现了排行榜以及数据存储了功能。接下来分享给大家,希望对有相关问题的人有所帮助。
先说一下UserDefault的用法,
主要方法:
设置一个键值和存放的数据 如果没有文件存在它会自动生成一个的
void setBoolForKey(const char* pKey, bool value); void setIntegerForKey(const char* pKey, int value); void setFloatForKey(const char* pKey, float value); void setDoubleForKey(const char* pKey, double value); void setStringForKey(const char* pKey, const std::string & value);
通过键读取数据,如果键不存在,可以设置一个defaultValue返回自己想要的值。
bool getBoolForKey(const char* pKey); int getIntegerForKey(const char* pKey); float getFloatForKey(const char* pKey); double getDoubleForKey(const char* pKey); std::string getStringForKey(const char* pKey);还有几个比较重要的
void flush () 将内容保存到xml文件
static const std::string & getXMLFilePath () 获取文件地址
static bool isXMLFileExist () 是否存在该文件
你用 set的语句设置了不少的值,然后用了flush()把他们存储起来了,但是发现你想要追加数据的时候只能再次使用flush()方法,这个时候如果你没有把原来的那些set语句重新设置一遍,他就会覆盖掉原来的数据。所以没有办法每一次获取一个,存储一个。达不到追加的效果(至少我找了真的很久都没有方法),最后我总结了一下,这个类应该是用于存储最高分,或者是系统设置的时候使用的!(个人感觉应该是这样的)
这个地址可以去看看 : http://www.cocos.com/doc/cocos2d-x-3.0/db/d94/classcocos2d_1_1_user_default.html
这样以后我实在是没有办法,所以去查了很多资料,发现好像可以用数据库,可以用FileUnit,可以用tinyxml地方法来实现本地存储。我没有学过这里的任何东西,如果有人学过数据库,就还是用数据库来写可能很方便。我最后选择了tinyxml2,发现cocos2dx 3.6 已经把它集成在自己的类库里面了,所以不用再去网上下载了。
下面贴上我的代码
void GameScenePop::getPageXML(const char *fileName)
{
//记录姓名并且传递到英雄榜
auto pastname = (TextFieldTTF *)this->getChildByTag(TAG_MENU_TXTFILED);
pastname->detachWithIME(); //关闭输入框
std::string winName = pastname->getString(); //存放名字
char * charwinName = new char[30];
charwinName = (char*)winName.data();
//记录分数并且传递到英雄榜
auto pastscore = (Label *)this->getChildByTag(TAG_MENU_SCORE);
std::string winScore = pastscore->getString(); //转换格式
char * charwinScore = new char[30];
charwinScore = (char*)winScore.data();
/* sprintf(charwinScore, "%s", winScore);*/
int pastwinScore = atoi(charwinScore); //存放分数
std::string filePath = FileUtils::getInstance()->getWritablePath() + fileName;<span></span> <span></span>//路径加名字
tinyxml2::XMLDocument *pDoc = new tinyxml2::XMLDocument();
XMLError errorId = pDoc->LoadFile(filePath.c_str());
if (errorId != 0) {
//xml格式错误
return;
}
XMLElement *rootEle = pDoc->RootElement(); //新建指针指向根节点
if (rootEle == nullptr) //如果没有根节点
{
//添加plist节点
XMLElement *plistElement = pDoc->NewElement("plist"); //新建节点
plistElement->SetAttribute("version", "1.0"); //设置里面的属性
pDoc->LinkEndChild(plistElement);
XMLComment *commentElement = pDoc->NewComment("this is xml comment"); //设置comment
plistElement->LinkEndChild(commentElement);
//添加dic节点
XMLElement *dicElement = pDoc->NewElement("dic"); //新建节点
plistElement->LinkEndChild(dicElement); //把节点添加在<span></span>plistElement节点下
//添加key节点
XMLElement *keyElement = pDoc->NewElement("data");
/*keyElement->LinkEndChild(pDoc->NewText("key"));*/
dicElement->LinkEndChild(keyElement); //把节点添加在<span></span>dicElement节点下
//添加key节点下 姓名
XMLElement *name = pDoc->NewElement("name");
name->LinkEndChild(pDoc->NewText(charwinName)); //给节点添加文本内容
keyElement->LinkEndChild(name);
//添加key节点下 分数
XMLElement *score = pDoc->NewElement("score");<span></span> //给节点添加文本内容
score->LinkEndChild(pDoc->NewText(charwinScore));
keyElement->LinkEndChild(score);
}
else
{
XMLElement *dicEle = rootEle->FirstChildElement(); //设置一个指针指向根结点的第一个子孩子
if (dicEle == nullptr) //如果没有dic节点
{
//添加dic节点
XMLElement *dicElement = pDoc->NewElement("dic");
rootEle->LinkEndChild(dicElement);
//添加key节点
XMLElement *keyElement = pDoc->NewElement("data");
/*keyElement->LinkEndChild(pDoc->NewText("key"));*/
dicEle->LinkEndChild(keyElement);
//添加key节点下 姓名
XMLElement *name = pDoc->NewElement("name");
name->LinkEndChild(pDoc->NewText(charwinName));
keyElement->LinkEndChild(name);
//添加key节点下 分数
XMLElement *score = pDoc->NewElement("score");
score->LinkEndChild(pDoc->NewText(charwinScore));
keyElement->LinkEndChild(score);
}
else
{
XMLElement *keyEle = dicEle->FirstChildElement(); //设置一个指针指向dicELe的第一个子孩子
int ii = 1;
for (int i = 0; i < ii; i++) //继续添加key节点
{
int can = 0;
if (keyEle == nullptr)
{
//添加key节点
XMLElement *keyElement = pDoc->NewElement("data");
/*keyElement->LinkEndChild(pDoc->NewText("key"));*/
dicEle->LinkEndChild(keyElement);
//添加key节点下 姓名
XMLElement *name = pDoc->NewElement("name");
name->LinkEndChild(pDoc->NewText(charwinName));
keyElement->LinkEndChild(name);
//添加key节点下 分数
XMLElement *score = pDoc->NewElement("score");
score->LinkEndChild(pDoc->NewText(charwinScore));
keyElement->LinkEndChild(score);
can = 1;
}
if (can==0)
{
keyEle = keyEle->NextSiblingElement(); //指针指向下一个兄弟节点
ii++; //用来记录一共存在的节点
}
can = 0;
}
input = ii; //把节点数统计起来
}
}
//CCLOG("chenggonglema");
pDoc->SaveFile(filePath.c_str()); //把操作变化存储起来在xml文件里面
pDoc->Print();
delete pDoc;
}
里面有一些是我自己的其他参数,大家不用看。 我想分享的是它的基本语法,注释里面我特意写详细了,大家看看每句代码是什么意思就好。
新建出来的xml文件是这样的:
<plist version="1.0">
<!--this is xml comment-->
<dic>
<data>
<name>LuChaoyu</name>
<score>99966</score>
</data>
</dic>
</plist>
其中LuChaoyu和99966 是我在文本框输入的姓名以及游戏得分。
然后每一次都添加data节点就好了。
以下是获取的代码,我写在另一个场景中:
void Poplayer::getPageXML(const char *fileName)
{
outPut=UserDefault::getInstance()->getIntegerForKey("input");
clean = true;
std::string filePath = FileUtils::getInstance()->getWritablePath() + fileName;
tinyxml2::XMLDocument *pDoc = new tinyxml2::XMLDocument();
XMLError errorId = pDoc->LoadFile(filePath.c_str());
if (errorId != 0) {
//xml格式错误
return;
}
XMLElement *rootEle = pDoc->RootElement();
XMLElement *dicEle = rootEle->FirstChildElement();
XMLElement *datatEle = dicEle->FirstChildElement();
for (int i = 0; i < outPut; i++)
{
//获取姓名
XMLElement *winnameEle = datatEle->FirstChildElement("name"); //寻找子节点name
if (winnameEle)
{
log("keyEle Text= %s", winnameEle->GetText()); //获取里面的内容
UserDefault::getInstance()->setStringForKey("mname", winnameEle->GetText());
}
//获取分数
XMLElement *winscoreEle = winnameEle->NextSiblingElement("score"); //寻找下一个兄弟节点score
if (winscoreEle)
{
log("childEle Text= %s", winscoreEle->GetText());
std::string winScore = winscoreEle->GetText(); //转换格式
char * charwinScore = new char[30];
charwinScore = (char*)winScore.data();
/* sprintf(charwinScore, "%s", winScore);*/
int pastwinScore = atoi(charwinScore); //存放分数
UserDefault::getInstance()->setIntegerForKey("mscore", pastwinScore);
}
getnamescore();
datatEle = datatEle->NextSiblingElement(); //指向下一个兄弟节点
}
//CCLOG("chenggonglema");
delete pDoc;
}
总体就是这些,这里没有涉及到删除节点等方法,等日后研究好再来发,完善一下。最近在写AI五子棋功能,没啥时间研究这个了......
希望这些可以帮到大家,谢谢~~