从零开始の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;
}

暂存

posted @ 2019-11-21 20:14  软不隆咚的二更  阅读(290)  评论(0编辑  收藏  举报