• creator 里 director 流程


    cc.Director

    cc.Director 继承自 EventTarget(前面分析过),
    所以 cc.Director 也有 分发事件, 监听事件,发布事件的能力.

    其包含的几个关键属性:

    	// Scheduler for user registration update
        this._scheduler = null;    
        // Scheduler for life-cycle methods in component
        this._compScheduler = null;
        // Node activator
        this._nodeActivator = null;
        // Action manager
        this._actionManager = null;
    

    解释一下里面几个东西的作用.
    a. this._scheduler 一个全局的调度器. _actionManager,_collisionManager,_physicsManager 都直接注册这这上面.
    我们一般不需要用这个.

    b. this._compScheduler 和 this._nodeActivator
    这两个东西其实互相一起作用的. 在加载完scene后,或者切换scene,要进行显示之前,
    会调用 scene 的 _activate方法. 在director::runSceneImmediate 这方法里面:

    scene._activate();
    

    这个 _activate 方法,就会通过 director的 _nodeActivator 这东西的 activateNode 方法进行激活:
    NodeActivator::_activateNodeRecursively

    	this._activateNodeRecursively(node, task.preload, task.onLoad, task.onEnable);
    

    这里面node就是加载的scene, 先激活scene上的 component(NodeActivator::activateComp).
    然后再对 scene 上的子节点进行递归调用 _activateNodeRecursively.

    在激活node的时候(NodeActivator::activateComp方法),

     cc.director._compScheduler.enableComp(comp, onEnableInvoker);
    

    在 ComponentScheduler::enableComp 里,又会调用 ComponentScheduler::_onEnabled(comp)这方法,
    如果当前正在更新,就放到 scheduleInNextFrame 这个数组中,下一帧来处理,
    否则就 ComponentScheduler::_scheduleImmediate 调用这方法,

    	_scheduleImmediate (comp) {
            if (comp.start && !(comp._objFlags & IsStartCalled)) {
                this.startInvoker.add(comp);
            }
            if (comp.update) {
                this.updateInvoker.add(comp);
            }
            if (comp.lateUpdate) {
                this.lateUpdateInvoker.add(comp);
            }
        },
    

    director的 this._compScheduler 这家伙,里面包含:
    ComponentScheduler::ctor()

    	function ctor () {
        // invokers
        this.startInvoker = new OneOffInvoker(createInvokeImpl(
            CC_EDITOR ? callStartInTryCatch : callStart));
        this.updateInvoker = new ReusableInvoker(createInvokeImpl(
            CC_EDITOR ? callUpdateInTryCatch : callUpdate, true));
        this.lateUpdateInvoker = new ReusableInvoker(createInvokeImpl(
            CC_EDITOR ? callLateUpdateInTryCatch : callLateUpdate, true));
    
        // components deferred to next frame
        this.scheduleInNextFrame = [];
    
        // during a loop
        this._updating = false;
    }
    

    在 _scheduleImmediate 方法中,就将scene中所有节点的组件,
    按照从scene开始 递归下来 全部加入到 这几个 invoker里面了.
    然后,就会在 director::mainLoop 方法里,去更新了.

    引擎初始化后,会调用 自身的 init 方法,完成初始化:

    1. 创建调度器.
    this._scheduler = new Scheduler();
    
    1. 创建 ActionManager, 并且启动.
    	if (cc.ActionManager) {
    		this._actionManager = new cc.ActionManager();
    		this._scheduler.scheduleUpdate(this._actionManager, Scheduler.PRIORITY_SYSTEM, false);    
    	} else {
    		this._actionManager = null;
    	}
    
    1. 创建 组件调度器和 NodeActivator(管理节点的激活)
    	this._compScheduler = new ComponentScheduler();
    	this._nodeActivator = new NodeActivator();
    
    1. 创建 动画管理器,并且启动.
    	if (cc.AnimationManager) {
    		this._animationManager = new cc.AnimationManager();
    		this._scheduler.scheduleUpdate(this._animationManager, Scheduler.PRIORITY_SYSTEM, false);
    	}
    	else {
    		this._animationManager = null;
    	}
    
    1. 创建碰撞管理器,并且启动.
    	// collision manager
    	if (cc.CollisionManager) {
    		this._collisionManager = new cc.CollisionManager();
    		this._scheduler.scheduleUpdate(this._collisionManager, Scheduler.PRIORITY_SYSTEM, false);
    	}
    	else {
    		this._collisionManager = null;
    	}
    
    1. 创建物理引擎管理器,并且启动.
    	// physics manager
    	if (cc.PhysicsManager) {
    		this._physicsManager = new cc.PhysicsManager();
    		this._scheduler.scheduleUpdate(this._physicsManager, Scheduler.PRIORITY_SYSTEM, false);
    	}
    	else {
    		this._physicsManager = null;
    	}
    
    1. 创建控件管理器
    	// WidgetManager
    	if (cc._widgetManager) {
    		cc._widgetManager.init(this);
    	}
    

    mainLoop 方法

    1. 先计算 dt
    this.calculateDeltaTime();
    
    1. 更新. 主要是组件的更新
    	// Update
    	if (!this._paused) {
    		this.emit(cc.Director.EVENT_BEFORE_UPDATE);
    		// Call start for new added components
    		this._compScheduler.startPhase();
    		// Update for components
    		this._compScheduler.updatePhase(this._deltaTime);
    		// Engine update with scheduler
    		this._scheduler.update(this._deltaTime);
    		// Late update for components
    		this._compScheduler.lateUpdatePhase(this._deltaTime);
    		// User can use this event to do things after update
    		this.emit(cc.Director.EVENT_AFTER_UPDATE);
    		// Destroy entities that have been removed recently
    		Obj._deferredDestroy();
    	}
    

    所有节点的 component 都在 _compScheduler 这里面,
    startPhase 里面调用一些 onload start 这些一次性方法(只调用一次).
    updatePhase 就调用组件中的 update 方法.
    this._scheduler.update(this._deltaTime); 就只执行注册的 actionManager collisionManager physicsManager 这些更新.
    lateUpdatePhase 调用 lateUpdate 方法.

    发射 EVENT_AFTER_UPDATE 事件, 这时,WidgetManager 就会计算 widget 这些东西.
    见 WidgetManager::refreshScene 方法.

    1. 渲染
    renderer.render(this._scene);
    

    注意: 这里面的 renderer. 是cc.renderer, 不是 renderEngine里面的那个 renderer.
    这个 renderer 创建webgl环境,使用 ForwardRenderer 去做渲染.
    renderEngine里面那个renderer,就只是包含渲染使用的工具.

    当前renderer 在 cocos2d/core/renderer/index.js 里面,
    在 initWebGL 方法里,
    创建了用于渲染需要的东西:

    this.device = new renderEngine.Device(canvas, opts);
    this.scene = new renderEngine.Scene();
    this._walker = new RenderComponentWalker(this.device, this.scene);
    this._forward = new renderEngine.ForwardRenderer(this.device, builtins);
    

    看 renderer.render 方法:

    // walk entity component scene to generate models
    this._walker.visit(ecScene);
    // Render models in renderer scene
    this._forward.render(this.scene);
    

    调用了 walker:visit 这个方法,这个方法中最重要的是:

    RenderFlow.render(scene);
    
    function render (scene) {
        if (scene._renderFlag & WORLD_TRANSFORM) {
            _walker.worldMatDirty ++;
            scene._calculWorldMatrix();
            scene._renderFlag &= ~WORLD_TRANSFORM;
    
            flows[scene._renderFlag]._func(scene);
    
            _walker.worldMatDirty --;
        }
        else {
            flows[scene._renderFlag]._func(scene);
        }
    }
    

    flows[scene._renderFlag]._func(scene); 主要是这一句.
    这一句会从 scene开始,按照:

    const DONOTHING = 0;
    const LOCAL_TRANSFORM = 1 << 0;
    const WORLD_TRANSFORM = 1 << 1;
    const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM;
    const UPDATE_RENDER_DATA = 1 << 2;
    const OPACITY = 1 << 3;
    const COLOR = 1 << 4;
    const RENDER = 1 << 5;
    const CUSTOM_IA_RENDER = 1 << 6;
    const CHILDREN = 1 << 7;
    const POST_UPDATE_RENDER_DATA = 1 << 8;
    const POST_RENDER = 1 << 9;
    

    这里面的顺序,依次检查scene的 _renderFlag.
    只要设置了,就调用相应的回调函数, 回调函数全部在 render-flow.js 里面.
    当调用到 _children 这个回调的时候, 黑魔法来了.

    会对scene的子节点又进行一次从上到下的检查. 直到场景树上所有的node全部更新完毕.
    其实最核心更新的 就是 node 的模型矩阵,颜色,opacity.

    在render-flow 中回调 _render 的时候,
    会检查使用的材质,如果当前的和调用的 component 的材质不一样,
    则需要将前面的 _flush一次, 会使用 model 来暂存.

    接着调用:

     this._forward.render(this.scene);
    

    2d中使用 main camera,去渲染 render_scene.
    这个render_scene是 walk里面创建的scene,不是 director._scene.

    然后就会调用到 Base::_render 这个方法,
    此方法里面设置好渲染环境,
    从models中把数据拿出来,
    然后 在render stages里面,回调 forwardrenderer 里面 注册的 _transparentStage方法.

    // render stages
      for (var i$2 = 0; i$2 < _stageInfos.length; ++i$2) {
        var info = _stageInfos.data[i$2];
        var fn = this$1._stage2fn[info.stage];
    
        fn(view, info.items);
      }
    

    就是 fn(view, info.items); 调用下面的函数:

     ForwardRenderer.prototype._transparentStage = function _transparentStage (view, items) {
        var this$1 = this;
    
        // update uniforms
        this._device.setUniform('view', mat4.array(_a16_view, view._matView));
        this._device.setUniform('proj', mat4.array(_a16_proj, view._matProj));
        this._device.setUniform('viewProj', mat4.array(_a16_viewProj, view._matViewProj));
    
        // draw it
        for (var i = 0; i < items.length; ++i) {
          var item = items.data[i];
          this$1._draw(item);
        }
      };
    

    然后有调用到: Base.prototype._draw,再在 Base::_draw里面
    调用 device.draw(ia._start, count); 进行最终的绘制.

  • 相关阅读:
    Direct2D 几何计算和几何变幻
    ORACLE触发器具体解释
    HI3518E用J-link烧写裸板fastboot u-boot流程
    NYOJ
    使用ServletFileUpload实现上传
    再看数据库——(2)视图
    cookie登录功能实现
    耗时输入框
    Android开发 ----------怎样真机调试?
    Windows搭建Eclipse+JDK+SDK的Android --安卓开发入门级
  • 原文地址:https://www.cnblogs.com/daihanlong/p/10451778.html
Copyright © 2020-2023  润新知