外观
Stage02|Engine Loop
Lesson011|cc.game 启动后发生了什么?
一、本课目标
理解 Cocos Creator 游戏启动后,引擎大概经历了什么流程。
本课重点不是背源码,而是建立这条主线:
text
cc.game 启动游戏
↓
cc.director 接管场景
↓
加载 Scene
↓
创建 Node 和 Component
↓
执行生命周期
↓
进入主循环
↓
每帧调用 update / lateUpdate
↓
渲染到屏幕二、cc.game 是什么?
cc.game 可以理解成:
Cocos Creator 游戏运行时的总入口 / 总开关 / 总管家。
它负责:
text
初始化游戏
初始化引擎配置
初始化渲染环境
启动主循环
暂停游戏
恢复游戏
结束游戏它不是某个节点,也不是某个组件。
你平时写的:
ts
onLoad() {}
onEnable() {}
start() {}
update(dt) {}不是自己主动执行的,而是被引擎启动后的主循环调度出来的。
三、cc.game 启动后的大流程
游戏启动后,可以粗略理解成:
text
游戏启动
↓
cc.game.run()
↓
初始化引擎配置
↓
初始化渲染环境
↓
初始化资源系统
↓
初始化事件系统
↓
启动 cc.director
↓
加载首场景
↓
创建场景节点树
↓
创建节点上的组件
↓
执行组件生命周期
↓
进入主循环
↓
每帧 tick核心关系:
text
cc.game:负责游戏启动和主循环
cc.director:负责场景管理和每帧调度
Scene / Node / Component:被调度和管理的对象
Renderer:负责把结果画出来四、cc.game 和 cc.director 的区别
可以这样记:
text
cc.game:游戏级别
cc.director:场景级别类比:
text
cc.game 像公司老板
cc.director 像项目经理
Scene 像当前项目
Node / Component 像具体员工cc.game 负责让整个游戏跑起来。
cc.director 负责让当前场景每帧往前推进。
所以:
ts
cc.game.pause();
cc.game.resume();是游戏级别的控制。
而:
ts
cc.director.loadScene("Main");是场景级别的控制。
五、update 是谁调用的?
你写的代码:
ts
update(dt) {
this.node.x += 10;
}不是自己运行的。
更准确的流程是:
text
cc.game 启动游戏主循环
↓
每帧驱动 cc.director.mainLoop
↓
director / scheduler / component scheduler 处理每帧调度
↓
找到符合条件的 Component
↓
调用组件上的 update(dt)所以 update 是组件的方法,不是 Node 的方法。
Node 本身没有业务 update,真正被调用的是挂在 Node 上的 Component。
六、组件的 update 想执行,需要满足什么条件?
一个组件的 update(dt) 能被执行,通常需要满足:
text
节点在场景树中
节点 activeInHierarchy = true
组件 enabled = true
组件实现了 update 方法
游戏主循环正在运行也就是说,不是你写了 update,它就一定会执行。
它必须处在引擎允许调度的状态里。
七、父节点 active=false,子节点 active=true,为什么子节点 update 不执行?
重点概念:
text
active
activeInHierarchyactive 表示节点自己想不想激活。
activeInHierarchy 表示节点在整个场景树中实际是否激活。
例如:
text
parent.active = false
child.active = true虽然子节点自己的 active 是 true,但是因为父节点关闭了,所以:
text
child.activeInHierarchy = false于是子节点上的组件不会被 update 调度。
正确理解是:
text
不是因为父节点 update 不执行,所以子节点 update 不执行
而是因为父节点 inactive 导致子节点 activeInHierarchy=false
所以子节点上的组件不再满足 update 调度条件八、生命周期顺序
场景加载后,节点和组件创建完成,引擎会执行组件生命周期。
常见顺序:
text
onLoad
↓
onEnable
↓
start
↓
update
↓
lateUpdate记忆方式:
text
onLoad:我出生了
onEnable:我可以工作了
start:正式开始前准备一次
update:每帧工作
lateUpdate:每帧收尾九、onLoad、onEnable、start 的区别
1. onLoad
适合做基础初始化。
ts
onLoad() {
this.hp = 100;
this.score = 0;
}理解:
text
组件被加载进来了,我先准备自己的基础数据。2. onEnable
当组件进入可用状态时触发。
ts
onEnable() {
cc.log("组件启用");
}如果节点或组件从关闭变成开启,可能再次触发 onEnable。
理解:
text
我现在可以参与工作了。3. start
start 通常在第一次 update 前执行一次。
它适合做需要等其他组件也初始化后再进行的逻辑。
ts
start() {
this.refreshUI();
}理解:
text
大家都差不多准备好了,我开始正式工作。十、一帧里大概发生什么?
游戏进入主循环后,每一帧大概会经历:
text
处理输入
↓
处理定时器 / scheduler
↓
执行 update
↓
执行 lateUpdate
↓
处理动画 / action
↓
更新节点变换
↓
收集渲染数据
↓
合批
↓
提交 GPU
↓
显示到屏幕这也是之前 Dirty Flag 和延迟更新能接上的地方。
例如:
ts
update(dt) {
this.node.x += 10;
this.node.y += 20;
this.node.scale = 2;
}这不代表 World Matrix 会立刻计算 3 次。
更合理的理解是:
text
修改 x
↓
标记 transform dirty
修改 y
↓
继续标记 dirty
修改 scale
↓
继续标记 dirty
本帧后续阶段
↓
统一计算 transform / world matrix
↓
统一参与渲染业务代码主要负责改状态。
引擎会在合适的阶段统一处理这些状态变化。
十一、component.enabled、node.active、cc.game.pause 的区别
1. component.enabled = false
ts
this.getComponent(MyScript).enabled = false;影响的是:
text
这个组件自己结果:
text
这个组件不再执行 update
但节点可能仍然显示
节点上的其他组件可能仍然工作
子节点不受它影响一句话:
text
enabled 管组件。2. node.active = false
ts
this.node.active = false;影响的是:
text
这个节点以及它的子节点结果:
text
当前节点不再 activeInHierarchy
子节点也会因为父节点关闭而 activeInHierarchy=false
相关组件不再 update
节点通常不再渲染一句话:
text
active 管节点树的一段。3. cc.game.pause()
ts
cc.game.pause();影响的是:
text
整个游戏主循环结果:
text
整个游戏的每帧推进暂停
update 不继续跑
dt 不继续推进
游戏整体暂停一句话:
text
pause 是全局暂停。十二、本课核心总结
cc.game 启动后,不是直接进入 update。
更完整的过程是:
text
cc.game 启动游戏
↓
初始化引擎和渲染环境
↓
cc.director 加载首场景
↓
创建 Scene / Node / Component
↓
执行 onLoad
↓
执行 onEnable
↓
执行 start
↓
进入 mainLoop
↓
scheduler / component scheduler 找到可执行组件
↓
调用组件的 update(dt)
↓
后续处理 transform / render / draw最终要记住一句话:
cc.game负责让游戏跑起来,cc.director负责让场景每帧往前推进,组件生命周期和 update 都是被引擎主循环调度出来的。
十三、本课过关答案
1. cc.game 和 cc.director 分别负责什么?
text
cc.game 负责游戏启动、暂停、恢复和主循环。
cc.director 负责场景管理和每帧调度。2. 谁调用 update?
text
cc.game 启动主循环,每帧驱动 cc.director.mainLoop。
director / scheduler / component scheduler 找到符合条件的组件,然后调用组件的 update(dt)。3. 父节点 active=false,子节点 active=true,子节点 update 会执行吗?
text
不会。
因为父节点 active=false 后,子节点虽然自己的 active 仍然可以是 true,
但是它的 activeInHierarchy 会变成 false。
所以子节点上的组件不满足 update 调度条件,update 不会执行。4. 生命周期顺序是什么?
text
onLoad → onEnable → start → update → lateUpdate5. component.enabled=false 和 node.active=false 的区别是什么?
text
component.enabled=false 只影响这个组件。
node.active=false 影响这个节点以及它的子节点。6. cc.game.pause() 和 node.active=false 的区别是什么?
text
cc.game.pause() 是全局暂停游戏主循环。
node.active=false 是局部关闭某个节点和它的子节点。7. 修改 x、y、scale 会立刻计算 3 次 World Matrix 吗?
text
通常不会。
这些修改主要会标记 dirty,真正的 transform / world matrix 计算会在本帧后续阶段统一处理。8. 一句话总结 cc.game 启动后到 update 被调用的过程
text
cc.game 启动游戏并初始化引擎和渲染环境,
cc.director 加载首场景,创建节点和组件,
执行 onLoad / onEnable / start,
然后在 mainLoop 中通过调度系统调用符合条件组件的 update(dt)。十四、下一课预告
下一课进入:
text
Stage02|Engine Loop
Lesson012|Director.mainLoop:一帧到底怎么跑?下一课会继续拆:
text
一帧的开始
↓
scheduler
↓
update
↓
lateUpdate
↓
transform
↓
render
↓
下一帧重点理解:
为什么你的业务代码不是“立刻生效到屏幕”,而是被一帧一帧地推进和统一处理。