资源加载
简而言之,cocos2d-x使用快速缓存机制(Cache)来缓存加载的资源,避免重复读取磁盘的开销。
(一)CSLoader
CSLoader
模块用于从CocosStudio导出的csb, json或ExportJson文件中加载相应的节点(Node
)、动画(ActionTimeline
)等。
1. 加载节点
- 直接调用
CSLoader::createNode
方法。e.g.auto node = CSLoader::createNode("MainScene.csb"); if (node) { addChild(node); }
CSLoader::createNode
:根据后缀选择对应的创建方法——二进制(csb)或 json(json/ExportJson)Node* CSLoader::createNode(const std::string& filename) { std::string path = filename; size_t pos = path.find_last_of('.'); std::string suffix = path.substr(pos + 1, path.length()); CSLoader* load = CSLoader::getInstance(); if (suffix == "csb") { return load->createNodeWithFlatBuffersFile(filename, nullptr); } else if (suffix == "json" || suffix == "ExportJson") { return load->createNodeFromJson(filename); } return nullptr; } Node* CSLoader::createNodeWithFlatBuffersFile(const std::string &filename, const ccNodeLoadCallback &callback) { Node* node = nodeWithFlatBuffersFile(filename, callback); reconstructNestNode(node); return node; }
CSLoader::nodeWithFlatBuffersFile
:使用FlatBuffer文件(二进制)创建节点。Node* CSLoader::nodeWithFlatBuffersFile(const std::string &fileName, const ccNodeLoadCallback &callback) { std::string fullPath = FileUtils::getInstance()->fullPathForFilename(fileName); // 绝对路径 Data buf = FileUtils::getInstance()->getDataFromFile(fullPath); auto csparsebinary = GetCSParseBinary(buf.getBytes()); // decode plist auto textures = csparsebinary->textures(); int textureSize = textures->size(); for (int i = 0; i < textureSize; ++i) { SpriteFrameCache::getInstance()->addSpriteFramesWithFile(textures->Get(i)->c_str()); // 将精灵帧添加到快速缓存中(如果有帧动画的话) } Node* node = nodeWithFlatBuffers(csparsebinary->nodeTree(), callback); // 递归创建节点树 return node; }
- 目前有个问题就是暂时不清楚什么时候会触发
addSpriteFramesWithFile
,即使在CocosStudio生成了帧动画,也不会在加载时触发精灵帧的快速缓存。但在方法CSLoader::loadSprite
会应用到(SpriteFrame* spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(path);
)。 - 关于精灵快速缓存和纹理快速缓存可以参考博客:我的Cocos2d-x學習筆記(七)紋理快取、幀快取、精靈的建立、zOrder
- 目前有个问题就是暂时不清楚什么时候会触发
2. 加载动画
- 直接调用
CSLoader::createTimeline
方法。ActionTimeline* action = CSLoader::createTimeline("MainScene.csb"); if (action) { node->runAction(action); action->gotoFrameAndPlay(0, false); }
CSLoader::createTimeline
:根据后缀选择对应的创建方法——二进制(csb)或 json(json/ExportJson)。ActionTimeline* CSLoader::createTimeline(const std::string &filename) { std::string suffix = getExtentionName(filename); ActionTimelineCache* cache = ActionTimelineCache::getInstance(); if (suffix == "csb") { return cache->createActionWithFlatBuffersFile(filename); } else if (suffix == "json" || suffix == "ExportJson") { return cache->createActionFromJson(filename); } return nullptr; }
ActionTimelineCache::createActionWithFlatBuffersFile
:判断一下动作是否已经存在,不存在就加载,否则直接返回clone。ActionTimeline* ActionTimelineCache::createActionWithFlatBuffersFile(const std::string &fileName) { ActionTimeline* action = _animationActions.at(fileName); if (action == NULL) { action = loadAnimationActionWithFlatBuffersFile(fileName); } return action->clone(); }
ActionTimelineCache::loadAnimationActionWithFlatBuffersFile
:从csb文件中加载数据,进一步调用createActionWithDataBuffer
函数。ActionTimeline* ActionTimelineCache::loadAnimationActionWithFlatBuffersFile(const std::string &fileName) { // if already exists an action with filename, then return this action ActionTimeline* action = _animationActions.at(fileName); if (action) return action; // 不是才判断过吗?为什么这里还要再判断一次? std::string path = fileName; std::string fullPath = FileUtils::getInstance()->fullPathForFilename(fileName); CC_ASSERT(FileUtils::getInstance()->isFileExist(fullPath)); Data buf = FileUtils::getInstance()->getDataFromFile(fullPath); action = createActionWithDataBuffer(buf); _animationActions.insert(fileName, action); return action; }
ActionTimelineCache::createActionWithDataBuffer
:获取动作,调用loadTimelineWithFlatBuffers
加载时间线。ActionTimeline* ActionTimelineCache::createActionWithDataBuffer(const cocos2d::Data& data) { auto csparsebinary = GetCSParseBinary(data.getBytes()); // 解析csb二进制文件 auto nodeAction = csparsebinary->action(); // 获取动作 auto action = ActionTimeline::create(); int duration = nodeAction->duration(); action->setDuration(duration); float speed = nodeAction->speed(); action->setTimeSpeed(speed); auto animationlist = csparsebinary->animationList(); int animationcount = animationlist->size(); for (int i = 0; i < animationcount; i++) { auto animationdata = animationlist->Get(i); AnimationInfo info; info.name = animationdata->name()->c_str(); info.startIndex = animationdata->startIndex(); info.endIndex = animationdata->endIndex(); action->addAnimationInfo(info); } auto timeLines = nodeAction->timeLines(); int timelineLength = timeLines->size(); std::multimap<std::string,timeline::Timeline*> properTimelineMap;// order the timelines depends property name for (int i = 0; i < timelineLength; i++) { auto timelineFlatBuf = timeLines->Get(i); Timeline* timeline = loadTimelineWithFlatBuffers(timelineFlatBuf); // 加载Timeline if (timeline) { properTimelineMap.emplace(timelineFlatBuf->property()->c_str(), timeline); } } for (const auto& properTimelinePair : properTimelineMap) { action->addTimeline(properTimelinePair.second); } return action; }
ActionTimelineCache::loadTimelineWithFlatBuffers
:根据不同的属性加载不同的帧。Timeline* ActionTimelineCache::loadTimelineWithFlatBuffers(const flatbuffers::TimeLine *flatbuffers) { Timeline* timeline = nullptr; // property std::string property = flatbuffers->property()->c_str(); if(property == "") return nullptr; if(property != "") { timeline = Timeline::create(); int actionTag = flatbuffers->actionTag(); timeline->setActionTag(actionTag); auto framesFlatbuf = flatbuffers->frames(); int length = framesFlatbuf->size(); for (int i = 0; i < length; i++) { auto frameFlatbuf = framesFlatbuf->Get(i); Frame* frame = nullptr; if (property == Property_VisibleForFrame) { auto boolFrame = frameFlatbuf->boolFrame(); frame = loadVisibleFrameWithFlatBuffers(boolFrame); } else if (property == Property_Position) { auto potisionFrame = frameFlatbuf->pointFrame(); frame = loadPositionFrameWithFlatBuffers(potisionFrame); } else if (property == Property_Scale) { auto scaleFrame = frameFlatbuf->scaleFrame(); frame = loadScaleFrameWithFlatBuffers(scaleFrame); } else if (property == Property_RotationSkew) { auto scaleFrame = frameFlatbuf->scaleFrame(); frame = loadRotationSkewFrameWithFlatBuffers(scaleFrame); } else if (property == Property_CColor) { auto colorFrame = frameFlatbuf->colorFrame(); frame = loadColorFrameWithFlatBuffers(colorFrame); } else if (property == Property_FrameEvent) { auto eventFrame = frameFlatbuf->eventFrame(); frame = loadEventFrameWithFlatBuffers(eventFrame); } else if (property == Property_FileData) { auto textureFrame = frameFlatbuf->textureFrame(); frame = loadTextureFrameWithFlatBuffers(textureFrame); } else if (property == Property_Alpha) { auto intFrame = frameFlatbuf->intFrame(); frame = loadAlphaFrameWithFlatBuffers(intFrame); } else if (property == Property_AnchorPoint) { auto scaleFrame = frameFlatbuf->scaleFrame(); frame = loadAnchorPointFrameWithFlatBuffers(scaleFrame); } else if (property == Property_ZOrder) { auto intFrame = frameFlatbuf->intFrame(); frame = loadZOrderFrameWithFlatBuffers(intFrame); } else if (property == Property_ActionValue) { auto innerActionFrame = frameFlatbuf->innerActionFrame(); frame = loadInnerActionFrameWithFlatBuffers(innerActionFrame); } else if (property == Property_BlendValue) { auto blendFrame = frameFlatbuf->blendFrame(); frame = loadBlendFrameWithFlatBuffers(blendFrame); } if (!frame) { CCLOG("frame is invalid."); continue; } timeline->addFrame(frame); } } return timeline; }
【参考资料】
[1] 我的Cocos2d-x學習筆記(七)紋理快取、幀快取、精靈的建立、zOrder
[2] Cocos2d-x 之精灵帧 SpriteFrame