从零开始のcocos2dx生活(九)CCBReader
NodeLoaderLibrary是用来存储节点加载器类型的类,通过registerDefaultNodeLoaders()可以注册所有默认类型的加载器
在CocosBuilder的使用手册中:
1、如果要使用自定义的加载器
//创建一个默认的节点加载器库对象
CCNodeLoaderLibrary * ccNodeLoaderLibrary = CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
//使用自己的节点加载器,第一个参数是节点加载器的名字,第二个参数是节点加载器的加载函数
ccNodeLoaderLibrary->registerCCNodeLoader("HelloCocosBuilderLayer", HelloCocosBuilderLayerLoader::loader());
我们来看一看第一个方法中中做了什么操作:
NodeLoaderLibrary * NodeLoaderLibrary::newDefaultNodeLoaderLibrary() {
//先是调用了librayr方法,但进去之后发现只是一行宏定义
//CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(NodeLoaderLibrary, library);
//再调到这个方法中,发现这是一个类似于create()的方法,用来创建NodeLoaderLibrary对象
//并将这个对象加入到内存自动管理中
NodeLoaderLibrary * ccNodeLoaderLibrary = NodeLoaderLibrary::library();
//给创建的对象注册一堆默认的节点加载器,放在下面一段代码中了
ccNodeLoaderLibrary->registerDefaultNodeLoaders();
//最后返回带了各种加载器的节点加载库对象
return ccNodeLoaderLibrary;
}
void NodeLoaderLibrary::registerDefaultNodeLoaders() {
this->registerNodeLoader("CCNode", NodeLoader::loader());
this->registerNodeLoader("CCLayer", LayerLoader::loader());
this->registerNodeLoader("CCLayerColor", LayerColorLoader::loader());
this->registerNodeLoader("CCLayerGradient", LayerGradientLoader::loader());
this->registerNodeLoader("CCSprite", SpriteLoader::loader());
this->registerNodeLoader("CCLabelBMFont", LabelBMFontLoader::loader());
this->registerNodeLoader("CCLabelTTF", LabelTTFLoader::loader());
this->registerNodeLoader("CCScale9Sprite", Scale9SpriteLoader::loader());
this->registerNodeLoader("CCScrollView", ScrollViewLoader::loader());
this->registerNodeLoader("CCBFile", CCBFileLoader::loader());
this->registerNodeLoader("CCMenu", MenuLoader::loader());
this->registerNodeLoader("CCMenuItemImage", MenuItemImageLoader::loader());
this->registerNodeLoader("CCControlButton", ControlButtonLoader::loader());
this->registerNodeLoader("CCParticleSystemQuad", ParticleSystemQuadLoader::loader());
}
再看看第二个方法:
void NodeLoaderLibrary::registerNodeLoader(const char * pClassName, NodeLoader * pNodeLoader) {
//先将加载器hold住
pNodeLoader->retain();
//将加载器以(加载器名,加载器)的格式存储在_nodeLoaders中
//_nodeLoaders是一张map,在.h文件中可以看到如下的定义,存储了所有的加载器
//typedef std::map<std::string, NodeLoader *> NodeLoaderMap;
this->_nodeLoaders.insert(NodeLoaderMapEntry(pClassName, pNodeLoader));
}
2、如果不使用自定义的加载器,只需要一行代码就可以创建默认的加载器对象了
CCNodeLoaderLibrary * ccNodeLoaderLibrary = CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
以上是创建加载器的对象的方法
如果需要加载ccbi文件,那么需要知道ccbi文件中的根节点是什么类型的对象,以及想要返回的值类型,选择合适的类型来定义加载ccbi文件,如下使用了粒子系统来定义加载的ccbi文件
CCParticleSystem* myParticles = (CCParticleSystem*) ccbReader->readNodeGraphFromFile("MyParticleSystem.ccbi");
.ccb文件是CCB项目的原始文件。是map键值对的形式,保存了项目中所有Node的信息。
.ccbi文件是CCB项目发布后的生成的二进制文件。CCBReader可以快速通过该二进制文件,读取并设置CCB项目内容到引擎中。
.ccbi文件是.ccb文件的精简,专门提供给CCBReader类进行解析。通过CCBReader,把项目中的Node和Node属性在引擎中新建Node并设置属性,从而把这些Node添加到Scene或Layer中。
//加载ccb文件
Node* CCBReader::readNodeGraphFromFile(const char *pCCBFileName)
{
return this->readNodeGraphFromFile(pCCBFileName, nullptr);
}
Node* CCBReader::readNodeGraphFromFile(const char* pCCBFileName, Ref* pOwner)
{
return this->readNodeGraphFromFile(pCCBFileName, pOwner, Director::getInstance()->getWinSize());
}
//最后都调用这个方法
Node* CCBReader::readNodeGraphFromFile(const char *pCCBFileName, Ref *pOwner, const Size &parentSize)
{
if (nullptr == pCCBFileName || strlen(pCCBFileName) == 0)
{
return nullptr;
}
std::string strCCBFileName(pCCBFileName); //获取ccb文件的名字
std::string strSuffix(".ccb*i"); // 格式字符
// Add ccbi suffix
// 判断文件名没有.ccbi的后缀,如果没有就加上
if (!CCBReader::endsWith(strCCBFileName.c_str(), strSuffix.c_str()))
{
strCCBFileName += strSuffix;
}
//获取ccb文件的完整地址
std::string strPath = FileUtils::getInstance()->fullPathForFilename(strCCBFileName);
//将ccb文件完整地址转型为Data
auto dataPtr = std::make_shared<Data>(FileUtils::getInstance()->getDataFromFile(strPath));
//调用readNodeGraphFromData,下面一段
Node *ret = this->readNodeGraphFromData(dataPtr, pOwner, parentSize);
return ret;
}
Node* CCBReader::readNodeGraphFromDDData(std::shared_ptr<cocos2d::Data> data, Ref *pOwner, const Size &parentSize)
{
_data = data; //ccb完整路径
_bytes =_data->getBytes(); //将文件路径转换成char字符
_currentByte = 0;
_currentBit = 0;
_owner = pOwner; //跳转了几个函数没发现有什么用法,因为是Ref类型,猜测是可自定义参数
CC_SAFE_RETAIN(_owner);
_animationManager->setRootContainerSize(parentSize);
_animationManager->_owner = _owner;
//
Node *pNodeGraph = readFileWithCleanUp(true, std::make_shared<CCBAnimationManagerMap>());
//
if (pNodeGraph && _animationManager->getAutoPlaySequenceId() != -1)
{
// Auto play animations
_animationManager->runAnimationsForSequenceIdTweenDuration(_animationManager->getAutoPlaySequenceId(), 0);
}
// Assign actionManagers to userObject
for (auto iter = _animationManagers->begin(); iter != _animationManagers->end(); ++iter)
{
Node* pNode = iter->first;
CCBAnimationManager* manager = iter->second;
//
pNode->setUserObject(manager);
//不使用
if (_jsControlled)
{
_nodesWithAnimationManagers.pushBack(pNode);
_animationManagersForNodes.pushBack(manager);
}
}
return pNodeGraph;
}
Node* CCBReader::readFileWithCleanUp(bool bCleanUp, CCBAnimationManagerMapPtr am)
{
if (! readHeader())
{
return nullptr;
}
if (! readStringCache())
{
return nullptr;
}
if (! readSequences())
{
return nullptr;
}
//
setAnimationManagers(am);
//
Node *pNode = readNodeGraph(nullptr);
//
_animationManagers->insert(pNode, _animationManager);
if (bCleanUp)
{
cleanUpNodeGraph(pNode);
}
return pNode;
}
bool CCBReader::readStringCache() {
int numStrings = this->readInt(false);
for(int i = 0; i < numStrings; i++) {
this->_stringCache.push_back(this->readUTF8());
}
return true;
}
bool CCBReader::readSequences()
{
auto& sequences = _animationManager->getSequences();
int numSeqs = readInt(false);
for (int i = 0; i < numSeqs; i++)
{
CCBSequence *seq = new (std::nothrow) CCBSequence();
seq->autorelease();
seq->setDuration(readFloat());
seq->setName(readCachedString().c_str());
seq->setSequenceId(readInt(false));
seq->setChainedSequenceId(readInt(true));
if(!readCallbackKeyframesForSeq(seq)) return false;
if(!readSoundKeyframesForSeq(seq)) return false;
sequences.pushBack(seq);
}
_animationManager->setAutoPlaySequenceId(readInt(true));
return true;
}
//解析头部字节
bool CCBReader::readHeader()
{
/* If no bytes loaded, don't crash about it. */
if(this->_bytes == nullptr) {
return false;
}
/* Read magic bytes */
int magicBytes = *((int*)(this->_bytes + this->_currentByte));
this->_currentByte += 4;
if(CC_SWAP_INT32_BIG_TO_HOST(magicBytes) != (*reinterpret_cast<const int*>("ccbi"))) {
return false;
}
/* Read version. */
int version = this->readInt(false);
if(version != CCB_VERSION) {
log("WARNING! Incompatible ccbi file version (file: %d reader: %d)", version, CCB_VERSION);
return false;
}
// Read JS check
_jsControlled = this->readBool();
_animationManager->_jsControlled = _jsControlled;
return true;
}
暂存