标准周期
http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
creator提供了7种生命周期函数,分别是:onLoad,start,update,lateUpdate,onDestroy,onEnable,onDisable
。
其中:onDestroy,onEnable,onDisable
为触发式调用,可以参考官方文档,此处不说明。
另外4种的调用顺序是onLoad -> start -> update -> lateUpdate
。
在标准周期中插入方法
结论:onload -> test-function -> start -> update = > lateupdate
例子:有1个prefab和挂载在prefab上的脚本test,1个主脚本
// test.ts
const { ccclass, property } = cc._decorator;
@ccclass
export class test extends cc.Component {
onLoad() {
cc.log("onload")
}
start() {
cc.log("start")
}
flag_update = true
update() {
if (this.flag_update) {
this.flag_update = false
cc.log("update")
}
}
flag_late_update = true
lateUpdate() {
if (this.flag_late_update) {
this.flag_late_update = false
cc.log("lateupdate")
}
}
test() {
cc.log("test-function")
}
}
// 主脚本
******
onLoad() {
this.create_some_node()
}
@property(cc.Prefab)
some_prefab: cc.Prefab = null
create_some_node() {
let n = cc.instantiate(this.some_prefab)
n.parent = this.node
n.getComponent(test).test()
}
******
scheduleOnce()
在update()
之前还是之后?
结论:update -> scheduleOnce
// 修改脚本 test.ts
******
onLoad() {
this.scheduleOnce(() => {
cc.log("onload")
}, 0)
}
start() {
this.scheduleOnce(() => {
cc.log("start")
}, 0)
}
******
原理浅析:帧
- 游戏内所有的逻辑以帧为基础。
- 引擎可以做到渲染帧、逻辑帧、物理帧等分离。cocos-creator中渲染帧和逻辑帧未分离。
// 将test.ts改回去,无schedule
// 修改主脚本,以3帧为例子
******
onLoad() {
// this.create_some_node()
}
count = 0
update() {
if (this.count < 3) {
cc.log("update:", this.count)
for (let i = 0; i < 1000; i += 1) {
cc.log(1) // 本项目是为了阻塞帧的执行
}
if (this.count === 1) {
this.create_some_node()
}
this.count += 1
}
}
******
执行结果为:
可以从结果看出,除了循环会阻碍帧的进程以外,子函数create_some_node
也会阻碍帧的进程,并且在此帧内会执行到子脚本的start方法。
优化方向1:减少单帧内的计算,放到多帧去执行
这点的逻辑很容易理解,即将一些无关的计算从单帧放到多帧中去执行。
creator中的api:schedule()中参数interval=0是为间隔帧执行,或者传入时间也可以了。
(错误的)优化方向2:异步化
由于js单线程的原因,即使是异步的promise也会一定程度上的阻塞执行。
在creator中则体现在:在某一帧中使用的promise,一定会在当前帧中执行完毕。
// 清理主脚本,仅创建,无其他调用或者输出
// 修改test.ts
******
onLoad() {
cc.log("onload")
}
start() {
cc.log("start")
}
count = 0
update() {
if (this.count < 5) {
cc.log("update", this.count)
if (this.count === 0) {
this.test()
}
this.count += 1
}
}
test() {
Promise.resolve().then(() => {
for (let i = 0; i < 1000; i += 1) {
cc.log(1)
}
})
cc.log("test-function")
}
******
执行结果为:
可以看到,1000次输出被卡在第1帧中了。