cocos3——10.cocos2dx架构复习

前端之家收集整理的这篇文章主要介绍了cocos3——10.cocos2dx架构复习前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1.内存管理

引用计数类Ref,构造时计数为1,retain+1,release-1(减到0就delete掉)。

Ref的autorelease将它添加自动释放池去,将在当前帧结束时被release一次(即如果中途未被retain则会被释放掉)。

另外cocos2dx内置的一些容器比如Vector、Map,在添加删除的时候会对元素进行retain和release。所以当你addChild的时候,里面_children.pushBack(child)就会将其引用计数加1,这样就不会被自动释放掉了。


2.ui树

通常我们使用的节点的坐标是其相对于父级节点的相对坐标。而每个元素的本地坐标系是以元素的 左下角为原点(注意不是以锚点处为原点!),向右上为正轴。

而节点的坐标指的是节点锚点处在父亲坐标系的位置,即相对于父亲左下角的位置。

node->convertToWorldSpace(pos)是将相对于node左下角的坐标转换到世界坐标,所以这里pos如果是node的坐标的话结果就是node左下角的世界坐标。

node->convertToWorldSpaceAR(pos)是将相对于node锚点的坐标转换到世界坐标,所以这里pos如果是Zero的话结果就是node锚点处的世界坐标。

所以获取node的世界坐标有两种方法:一种是通过父亲将node的位置转换到worldSpace,另一种是convertToWorldSpaceAR(Vec2::ZERO)。

所以在编写包含多个子节点的控件时,应该将这些子节点和父节点的左下角对齐,而不是和其锚点对齐。因为父节点的锚点不管怎么变,子节点跟他的关系都是固定的。


3.逻辑深度

节点现在有globalZOrder(默认为0),决定节点的渲染顺序(command的执行顺序)。

void RenderQueue::push_back(RenderCommand* command)
{
    float z = command->getGlobalOrder();
    if(z < 0)
    {
        _commands[QUEUE_GROUP::GLOBALZ_NEG].push_back(command);
    }
    else if(z > 0)
    {
        _commands[QUEUE_GROUP::GLOBALZ_POS].push_back(command);
    }
    else
    {
        if(command->is3D())
        {
            if(command->isTransparent())
            {
                _commands[QUEUE_GROUP::TRANSPARENT_3D].push_back(command);
            }
            else
            {
                _commands[QUEUE_GROUP::OPAQUE_3D].push_back(command);
            }
        }
        else
        {
            _commands[QUEUE_GROUP::GLOBALZ_ZERO].push_back(command);
        }
    }
}
这个是在渲染队列添加渲染命令时用到,将不同globalZOrder的节点放到不同的命令集合去。然后在渲染时从负到正进行渲染,详见Renderer::visitRenderQueue。

节点的遍历visit顺序和之前一样,通过localZOrder(就是2.x的zorder)从小到大进行。

        //visit the scene
        visit(renderer,transform,0);
        renderer->render();
总的来说,场景的渲染流程:通过localZOrder遍历visit所有节点,在里面调用节点的draw添加command到各自globalZOrder对应的命令集合去,然后渲染器再依次执行命令集合。注意 因为SpritebatchNode是将子元素组织成一个BatchCommand,会被统一添加到一个globalZOrder对应的命令集去渲染,所以给其子元素设置不同的globalZOrder是没有效果的。

4.场景管理

Director里提供了一些scene的管理方法,比如runWith、replace、push、pop、popToRoot等,但引擎永远只会渲染一个scene,所以不会有同时渲染两个scene的可能。所以要实现多个窗口同时渲染就需要自己在scene里面实现,而不能通过多个scene。所以最好把scene当成一个大的场景模块(即表示当前很长一段时间都执行与此相关的逻辑),比如login、main等,再在大模块内部进行窗口管理。


5.实时更新

scheduler会按优先级 从小到大进行更新回调。ActionManager优先级是最小的(也就是最高的,最先执行):

// action manager
    _actionManager = new (std::nothrow) ActionManager();
    _scheduler->scheduleUpdate(_actionManager,Scheduler::PRIORITY_SYSTEM,false);
而node的scheduleUpdate默认优先级是0:
void Node::scheduleUpdate()
{
    scheduleUpdateWithPriority(0);
}
而node的schedule不能设置优先级。原因是Scheduler里有4个容器:_updatesNegList,_updates0List,_updatesPosList,_hashForTimers。然后它update的时候也是按这个顺序更新的。scheduleUpdate的节点就放大前面3个容器,而schedule的就放到最后一个容器(则最后更新)。

在这些都更新完之后,还会执行一些异步函数(主要是其他线程 需要在主线程执行逻辑时使用):

    //
    // Functions allocated from another thread
    //

    // Testing size is faster than locking / unlocking.
    // And almost never there will be functions scheduled to be called.
    if( !_functionsToPerform.empty() ) {
        _performMutex.lock();
        // fixed #4123: Save the callback functions,they must be invoked after '_performMutex.unlock()',otherwise if new functions are added in callback,it will cause thread deadlock.
        auto temp = _functionsToPerform;
        _functionsToPerform.clear();
        _performMutex.unlock();
        for( const auto &function : temp ) {
            function();
        }
        
    }

猜你在找的Cocos2d-x相关文章