转自:blog.csdn.net/eduwc/article/details/9858723
在开始解析之前,先和大家说下如何阅读本文。
1.由于涉及到一些类的跳转,所以在有出现(跳XX)的地方,大家就可以利用搜索 搜索到相应的目的地查看 如果没有在系列文章深度解析cocostudio是如何处理动作编辑器导出来的Json文件(1)中,请到深度解析cocostudio是如何处理动作编辑器导出来的Json文件(2)中查找
2.本文章都是先上代码,然后再来做具体分析(其中一些不是很重要的就直接跟写在代码后面了)
我们来看一看cocostudio如何解析动画的
首先是加载动画文件
cs::ArmatureDataManager::sharedArmatureDataManager()->addArmatureFileInfo("NewProject","", "NewProject0.png","NewProject0.plist", "NewProject.json");
ArmatureDataManager 这个就是管理动画数据的大管家了
sharedArmatureDataManager 这个是一个单例,用来创建ArmatureDataManager的
我们再来深入看下addArmatureFileInfo是如何把json的动画信息加载进来并且解析的
先上源码,再来逐步分析
void ArmatureDataManager::addArmatureFileInfo(const char *armatureName, const char *useExistFileInfo, const char *imagePath, const char *plistPath, const char *configFilePath)
{
ArmatureFileInfo *fileInfo = (ArmatureFileInfo*)m_pArmatureFileInfoDic->objectForKey(armatureName);
if(!fileInfo)
{
fileInfo = ArmatureFileInfo::create();
fileInfo->armatureName = armatureName;
fileInfo->configFilePath = configFilePath;
fileInfo->useExistFileInfo = useExistFileInfo;
if (fileInfo->useExistFileInfo.compare("") != 0)
{
fileInfo = (ArmatureFileInfo*)m_pArmatureFileInfoDic->objectForKey(fileInfo->useExistFileInfo);
}
m_pArmatureFileInfoDic->setObject(fileInfo, fileInfo->armatureName);
}
DataReaderHelper::addDataFromFile(configFilePath);
for (std::vector
{
if (it->imagePath.compare(imagePath) == 0)
{
return;
}
}
ImageInfo imageInfo;
imageInfo.imagePath = imagePath;
imageInfo.plistPath = plistPath;
addSpriteFrameFromFile(plistPath, imagePath);
fileInfo->imageInfoVector.push_back(imageInfo);
}
分析
1. //作者考虑的很周到,会首先判断是否加载过了你所需要的Json文件,如果加载了 就直接根据名字来调取
ArmatureFileInfo *fileInfo = (ArmatureFileInfo*)m_pArmatureFileInfoDic->objectForKey(armatureName);
2.
//这边就是是重点了 这段代码开始解析Json,并且为你整理好数据格式,方便以后使用(跳1)
DataReaderHelper::addDataFromFile(configFilePath);
--------------------------------------------------------------华丽的分割线------------------------------------------------------------------------
(跳1)我们来看看addDataFromFile的具体实现
DataReaderHelper::addDataFromFile(configFilePath);
我们打开addDataFromFile来看下
void DataReaderHelper::addDataFromFile(const char *filePath)
{
/*
* Check if file is already added to ArmatureDataManager, if then return.
*/
for(unsigned int i = 0; i
if (m_arrConfigFileList[i].compare(filePath) == 0)
{
return;
}
}
m_arrConfigFileList.push_back(filePath);
std::string filePathStr = filePath;
size_t startPos = filePathStr.find_last_of(".");
std::string str = &filePathStr[startPos];
if (str.compare(".xml") == 0)
{
#if CS_TOOL_PLATFORM
if(Game::sharedGame()->isUsePackage())
{
DataReaderHelper::addDataFromXMLPak(filePathStr.c_str());
}
else
{
DataReaderHelper::addDataFromXML(filePathStr.c_str());
}
#else
DataReaderHelper::addDataFromXML(filePathStr.c_str());
#endif
}
else if(str.compare(".json") == 0 || str.compare(".ExportJson") == 0)
{
DataReaderHelper::addDataFromJson(filePathStr.c_str());
}
}
最开始又是一段检测是否添加的检测程序
for(unsigned int i = 0; i
if (m_arrConfigFileList[i].compare(filePath) == 0)
{
return;
}
}
解析
1.查看是xml文件还是json文件 根据不同文件做不同的处理(支持dragonbones导出的xml文件和cocostudio
动作编辑器导出Json文件)
std::string filePathStr = filePath;
size_t startPos = filePathStr.find_last_of(".");
std::string str = &filePathStr[startPos];
2. 根据上面的结果下面开始分别根据xml和json来做不同的处理,由于动作编辑器使用的是Json格式的,所以我们就先来主要
看下Json格式的解析 (要用到JsonCpp了 不是很了解的同学可以网上查看下)
if (str.compare(".xml") == 0)
{
#if CS_TOOL_PLATFORM
if(Game::sharedGame()->isUsePackage())
{
DataReaderHelper::addDataFromXMLPak(filePathStr.c_str());
}
else
{
DataReaderHelper::addDataFromXML(filePathStr.c_str());
}
#else
DataReaderHelper::addDataFromXML(filePathStr.c_str());
#endif
}
else if(str.compare(".json") == 0 || str.compare(".ExportJson") == 0)
{
我们重点看下DataReaderHelper::addDataFromJson(filePathStr.c_str())是如何来解析Json的(跳2)
DataReaderHelper::addDataFromJson(filePathStr.c_str());
}
--------------------------------------------------------------华丽的分割线------------------------------------------------------------------------
(跳2)
这边不需要太多的解析,主要就是读取文件了
void DataReaderHelper::addDataFromJson(const char *filePath)
{
unsigned long size;
std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(filePath);
const char *pFileContent = (char*)CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str() , "r", &size);
//把处理后的数据加入到缓存中
addDataFromJsonCache(pFileContent);
}
我们接着看 addDataFromJsonCache
void DataReaderHelper::addDataFromJsonCache(const char *fileContent)
{
CSJsonDictionary json;
json.initWithDescription(fileContent);//此处就是解析json的地方(跳3)
// Decode armatures
int length = json.getArrayItemCount(ARMATURE_DATA);
(跳4)
for (int i = 0; i
CSJsonDictionary *armatureDic = json.getSubItemFromArray(ARMATURE_DATA, i);
ArmatureData *armatureData = decodeArmature(*armatureDic);
ArmatureDataManager::sharedArmatureDataManager()->addArmatureData(armatureData->name.c_str(), armatureData);
}
// Decode animations
length = json.getArrayItemCount(ANIMATION_DATA);
for (int i = 0; i
CSJsonDictionary *animationDic = json.getSubItemFromArray(ANIMATION_DATA, i);
AnimationData *animationData = decodeAnimation(*animationDic);
ArmatureDataManager::sharedArmatureDataManager()->addAnimationData(animationData->name.c_str(), animationData);
}
// Decode textures
length = json.getArrayItemCount(TEXTURE_DATA);
for (int i = 0; i
CSJsonDictionary *textureDic = json.getSubItemFromArray(TEXTURE_DATA, i);
TextureData *textureData = decodeTexture(*textureDic);
ArmatureDataManager::sharedArmatureDataManager()->addTextureData(textureData->name.c_str(), textureData);
}
}
(跳3)
void CSJsonDictionary::initWithDescription(const char *pszDescription)
{
Json::Reader cReader;
m_cValue.clear();
if (pszDescription && *pszDescription)
{
std::string strValue = pszDescription;
//开始调用jsoncpp来解析json
cReader.parse(strValue, m_cValue, false);
}
}
解析 cReader.parse(strValue, m_cValue, false);
strValue 这个是要解析的字符串
m_cValue用来保存结果的 Json::Value 类型的变量
false 这个参数是用来决定是否要把注释也加进去的
按照官方的解释是
* \param collectComments \c true to collect comment and allow writing them back during
* serialization, \c false to discard comments.
* This parameter is ignored if Features::allowComments_
* is \c false.
下面来翻译下(英文不好 大家不要见怪啊)
如果设置成ture,就是可以再序列化的时候把注释也加进去
如果设置成false, 就是不添加注释
这个参数,如果在Features::allowComments_设置成false的时候就忽略
我们接着看parse 又嵌套了一层...水好深
bool
Reader::parse( const std::string &document,
Value &root,
bool collectComments )
{
document_ = document;
const char *begin = document_.c_str();//获取json内容
const char *end = begin + document_.length();//或者最后一个字符"\0"
return parse( begin, end, root, collectComments );
}
接着看return parse( begin, end, root, collectComments );
bool
Reader::parse( const char *beginDoc, const char *endDoc,
Value &root,
bool collectComments )
{
if ( !features_.allowComments_ )
{
collectComments = false;
}
begin_ = beginDoc;
end_ = endDoc;
collectComments_ = collectComments;
current_ = begin_;
lastValueEnd_ = 0;
lastValue_ = 0;
commentsBefore_ = "";
errors_.clear();
while ( !nodes_.empty() )
nodes_.pop();
nodes_.push( &root );
bool successful = readValue();
Token token;
skipCommentTokens( token );
if ( collectComments_ && !commentsBefore_.empty() )
root.setComment( commentsBefore_, commentAfter );
if ( features_.strictRoot_ )
{
if ( !root.isArray() && !root.isObject() )
{
// Set error location to start of doc, ideally should be first token found in doc
token.type_ = tokenError;
token.start_ = beginDoc;
token.end_ = endDoc;
addError( "A valid JSON document must be either an array or an object value.",
token );
return false;
}
}
return successful;
}
我们下节继续
--------------------------------------------------------------华丽的分割线------------------------------------------------------------------------