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 方法,完成初始化:
- 创建调度器.
this._scheduler = new Scheduler();
- 创建 ActionManager, 并且启动.
if (cc.ActionManager) {
this._actionManager = new cc.ActionManager();
this._scheduler.scheduleUpdate(this._actionManager, Scheduler.PRIORITY_SYSTEM, false);
} else {
this._actionManager = null;
}
- 创建 组件调度器和 NodeActivator(管理节点的激活)
this._compScheduler = new ComponentScheduler();
this._nodeActivator = new NodeActivator();
- 创建 动画管理器,并且启动.
if (cc.AnimationManager) {
this._animationManager = new cc.AnimationManager();
this._scheduler.scheduleUpdate(this._animationManager, Scheduler.PRIORITY_SYSTEM, false);
}
else {
this._animationManager = null;
}
- 创建碰撞管理器,并且启动.
// collision manager
if (cc.CollisionManager) {
this._collisionManager = new cc.CollisionManager();
this._scheduler.scheduleUpdate(this._collisionManager, Scheduler.PRIORITY_SYSTEM, false);
}
else {
this._collisionManager = null;
}
- 创建物理引擎管理器,并且启动.
// physics manager
if (cc.PhysicsManager) {
this._physicsManager = new cc.PhysicsManager();
this._scheduler.scheduleUpdate(this._physicsManager, Scheduler.PRIORITY_SYSTEM, false);
}
else {
this._physicsManager = null;
}
- 创建控件管理器
// WidgetManager
if (cc._widgetManager) {
cc._widgetManager.init(this);
}
mainLoop 方法
- 先计算 dt
this.calculateDeltaTime();
- 更新. 主要是组件的更新
// 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 方法.
- 渲染
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); 进行最终的绘制.