1.retain 和 release
Cocos2dx有一套内存管理机制。retain表示保持引用,以免被释放。一旦对象调用autorelease函数,这个对象就被cocos的内存管理机制盯上了,一旦他没有被认领,那他就会被释放。如下,他就会被内存机制自动释放:
// add "HelloWorld" splash screen" sp = Sprite::create("HelloWorld.png"); // position the sprite on the center of the screen sp->setPosition(Vec2(visibleSize.width/2 + origin.x,visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer //this->addChild(sprite,0);这样会导致在这个init函数执行完时,自动释放了sp。导致下面的调用出错:
void HelloWorld::menuCloseCallback(Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); return; #endif sp->getPosition(); Director::getInstance()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif }
sp->retain();(1)首先,要想让对象参与内存管理机制,必须继承Ref类(Node,Layer)等
(2)其次,调用对象的autorelease函数,对象就会被cocos2dx的内存管理机制盯上。一旦没人认领,就会释放。
(3)如果不想让对象被释放,那么就要调用对象的retain函数,一旦调用,就永远不会被内存管理机制杀掉。所以要调用release函数来进行释放。
(4)addChild();会调用retain函数,所以把对象添加到Layer时,就不需要再次调用retain函数了,当Layer释放时,他也会去调用子对象的release函数。
(5)当你把一个对象作为成员变量时,并且没有把对象addChild到另外一个对象时,就需要调用retain函数。
(6)最后,必须调用了autorelease函数之后,retain函数和release函数才会生效。一般create()函数都会调用autorelease函数。
Sprite* Sprite::create(const std::string & filename) { Sprite* sprite = new Sprite(); if(sprite && sprite->initWithFile(filename)) { sprite->autorelease();//retain release 必须有调用autorelease才会生效 return sprite; } .... }
2.数据保存
Cocos2dx提供保存数据的功能,类:UserDefault,他将数据保存到xml文件里,下次我们就直接从xml那里读取。适合简单的数据保存。
常用的api接口:
//set 数据
void setBoolForKey(const char* pKey,bool value); void setIntergerForKey(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);//get数据
bool getBoolForKey(const char* pKey); bool getBoolForKey(const char* pKey,bool defaultValue); int getIntegerForKey(const char* pKey); int getIntegerForKey(const char* pKey,int defaulerVaule); float getFloatForKey(const char* pKey); float getFloatForKey(const char* pKey,float defultValue); ...写个例子验证下:
UserDefault::getInstance()->setStringForKey("name","LLLdreamer"); std::string name = UserDefault::getInstance()->getStringForKey("name","none"); log("name = %s",name.c_str());
3.Csv配置文件读取
(1)首先来编写字符工具类,用于解析字符。
#ifndef _STRINGUTIL_H_ #define _STRINGUTIL_H_ #include "cocos2d.h" USING_NS_CC; class StringUtil:public Ref { public: static StringUtil* getInstance(); virtual bool init(); ValueVector split(const char* srcStr,const char* sSep); private: static StringUtil* m_StringUtil; }; #endifcpp文件
#include"StringUtil.h" StringUtil* StringUtil::m_StringUtil = NULL; StringUtil* StringUtil::getInstance()//单例 { if(m_StringUtil == NULL) { m_StringUtil = new StringUtil(); if(m_StringUtil && m_StringUtil->init()) { m_StringUtil->autorelease(); return m_StringUtil; } else { CC_SAFE_DELETE(m_StringUtil); m_StringUtil = NULL; } } return m_StringUtil; } bool StringUtil::init() { return true; } ValueVector StringUtil::split(const char* strSrc,const char* sSep)//和java的spit函数类似 { ValueVector stringList; int size = strlen(strSrc); Value str = Value(strSrc); int startIndex = 0; int endIndex = 0; endIndex = str.asString().find(sSep); std::string lineStr; while(endIndex > 0) { lineStr = str.asString().substr(startIndex,endIndex); stringList.push_back(Value(lineStr)); str = Value(str.asString().substr(endIndex+1,size)); endIndex = str.asString().find(sSep); } if(str.asString().compare("") != 0) { stringList.push_back(Value(str.asString())); } return stringList; }测试用例,可以正常的输出了:
auto strList = StringUtil::getInstance()->split("bingzong,dizong,tangzong,hongzong",","); for(auto value:strList) { log("value = %s",value.asString().c_str()); }(2)csv文件对象类
我们把csv文件当做一个对象来处理,新建一个CsvData对象,代表一份Csv文件数据。
#ifndef _CSVDATA_H_ #define _CSVDATA_H_ #include "cocos2d.h" USING_NS_CC; class CsvData:public Ref { public: CREATE_FUNC(CsvData); virtual bool init(); void addLineData(ValueVector lineData);//添加一行数据 ValueVector getStringLineData(int iLine);//获取某行数据 Size getRowColNum();//获取行列数据 private: ValueVector m_allLinesVec; int m_iColNum; }; #endif
#include"CsvData.h" void CsvData::addLineData(ValueVector lineData) { m_allLinesVec.push_back(Value(lineData)); m_iColNum = m_allLinesVec.size(); } ValueVector CsvData::getStringLineData(int iLine) { return m_allLinesVec.at(iLine).asValueVector(); } Size CsvData::getRowColNum() { Size size = Size(); size.width = m_allLinesVec.size(); if(size.width > 0) { size.height = m_allLinesVec.at(0).asValueVector().size(); } return size; } bool CsvData::init() { return true; }(3)csv文件读取的工具类
#ifndef _CSVUTIL_H_ #define _CSVUTIL_H_ #include "cocos2d.h" #include "CsvData.h" #include "StringUtil.h" USING_NS_CC; class CsvUtil:public Ref { public: static CsvUtil* getInstance(); virtual bool init(); void loadFile(const char* path);//加载配置文件 Value getValue(int iRow,int iCol,const char* csvFilePath);//获取某行某列的值 const std::string getString(int iRow,const char* csvFilePath);//获取值并转化为字符串 const int getInt(int iRow,const char* csvFilePath);//获取值并转换为整型 const Size getFileRowColNum(const char* csvFilePath);//获取行和列的数量 const int findValueIntWithLine(const char* chValue,int iValueCol,const char* csvFilePath); const float getFloat(int iRow,const char* csvFilePath); const bool getBool(int iRow,const char* csvFilePath); private: static CsvUtil* m_CsvUtil; Map<std::string,CsvData*> mCsvMap; }; #endif
#include "CsvUtil.h" CsvUtil* CsvUtil::m_CsvUtil = NULL; CsvUtil* CsvUtil::getInstance() { if(m_CsvUtil == NULL) { m_CsvUtil = new CsvUtil(); if(m_CsvUtil && m_CsvUtil->init()) { m_CsvUtil->autorelease(); m_CsvUtil->retain(); } else { CC_SAFE_DELETE(m_CsvUtil); m_CsvUtil = NULL; } } return m_CsvUtil; } bool CsvUtil::init() { return true; } const std::string CsvUtil::getString(int iRow,const char* csvFilePath) { Value colValue = getValue(iRow,iCol,csvFilePath); return colValue.asString(); } const int CsvUtil::getInt(int iRow,csvFilePath); return colValue.asInt(); } const float CsvUtil::getFloat(int iRow,csvFilePath); return colValue.asFloat(); } const bool CsvUtil::getBool(int iRow,csvFilePath); return colValue.asBool(); } void CsvUtil::loadFile(const char* sPath) { CsvData* csvdata = CsvData::create(); std::string str = FileUtils::getInstance()->getStringFromFile(sPath); ValueVector lineList = StringUtil::getInstance()->split(str.c_str(),"\n"); for(auto value:lineList) { ValueVector tArr = StringUtil::getInstance()->split(value.asString().c_str(),"); csvdata->addLineData(tArr); } mCsvMap.insert(sPath,csvdata); } const Size CsvUtil::getFileRowColNum(const char* csvFilePath) { auto csvData = mCsvMap.at(csvFilePath); if(csvData == nullptr) { loadFile(csvFilePath); csvData = mCsvMap.at(csvFilePath); } Size size = csvData->getRowColNum(); return size; } Value CsvUtil::getValue(int iRow,const char* csvFilePath) { auto csvData = mCsvMap.at(csvFilePath); if(csvData == nullptr) { loadFile(csvFilePath); csvData = mCsvMap.at(csvFilePath); } ValueVector rowVector = csvData->getStringLineData(iRow); Value colValue = rowVector.at(iCol); return colValue; }例子简单,不在赘述。
const char* sPath = "Monster.csv";//文件必须是存放在resource文件目录下,才能加载成功 CsvUtil::getInstance()->loadFile(sPath); Value firstMonsterName = CsvUtil::getInstance()->getValue(2,1,sPath); Value secondMonsterHP = CsvUtil::getInstance()->getValue(3,3,sPath); log("firstmonstername = %s",firstMonsterName.asString().c_str()); log("secondMonsterName = %s",secondMonsterHP.asString().c_str());
4.Json简介
Json也是一种文本文件,一种配置文件,他的格式与csv不一样,类似如下:{ “id”:1,"name":"bingzai","IQ":99.5 }有点类似map容器,一个key对应一个值。
那么如何解析json文件呢,我们直接用JsonCpp的库。可到这里下载:http://sourceforge.net/projects/jsoncpp/
下载解压后,只需要src/lib_json和include/json这两个目录。最后这两个文件的所有文件都都放到Class/Json目录下面。
这样进行编译还会报错,那么尝试在项目上选择属性,配置属性,C/C++,常规,附加包含目录,最前面加上../Classes
#include "json\writer.h" #include "json\reader.h" #include "json\value.h" void HelloWorld::readJson() { Json::Reader reader; Json::Value root; std::string data = FileUtils::getInstance()->getStringFromFile("test1.json"); if(reader.parse(data,root,false)) { log("id = %d",root["id"].asInt()); log("name = %s",root["name"].asCString()); log("IQ = %f",root["IQ"].asDouble()); } }另外,读取嵌套,数组类的JSON,还有写入的,直接参考以下接口:
void HelloWorld::readChildJson()//读取嵌套 { Json::Reader reader; Json::Value root; std::string data = FileUtils::getInstance()->getStringFromFile("test2.json"); if (reader.parse(data,false) == true) { log("id=%d",root["id"].asInt()); log("name=%s",root["name"].asCString()); log("IQ=%f",root["IQ"].asDouble()); log("msg value money=%d",root["msg"]["money"].asInt()); log("msg value say=%s",root["msg"]["say"].asCString()); } } void HelloWorld::readArrayJson()//数组类的JSON { Json::Reader reader; Json::Value root; std::string data = FileUtils::getInstance()->getStringFromFile("test3.json"); if (reader.parse(data,false) == true) { int iNum = root.size(); for (int i = 0; i < iNum; i++) { log("id=%d",root[i]["id"].asInt()); log("model=%s",root[i]["model"].asCString()); log("atk=%d",root[i]["atk"].asInt()); } } } void HelloWorld::writeJson()//写入 { Json::Value root; Json::FastWriter writer; root["name"] = "Who"; root["IQ"] = 999; std::string json_file = writer.write(root); FILE* file = fopen("testWirte.json","w"); fprintf(file,json_file.c_str()); fclose(file); }