cocos3——10.cocos2dx架构复习

10 篇文章 0 订阅

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();
        }
        
    }
  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值