Files
esengine/source/src/Utils/Coroutines/CoroutineManager.ts
2021-03-29 15:28:18 +08:00

155 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module es {
/**
* CoroutineManager用于隐藏Coroutine所需数据的内部类
*/
export class CoroutineImpl implements ICoroutine, IPoolable {
public enumerator: any;
/**
* 每当产生一个延迟它就会被添加到跟踪延迟的waitTimer中
*/
public waitTimer: number = 0;
public isDone: boolean;
public waitForCoroutine: CoroutineImpl;
public useUnscaledDeltaTime: boolean = false;
public stop() {
this.isDone = true;
}
public setUseUnscaledDeltaTime(useUnscaledDeltaTime: boolean) {
this.useUnscaledDeltaTime = useUnscaledDeltaTime;
return this;
}
public prepareForUse() {
this.isDone = false;
}
public reset() {
this.isDone = true;
this.waitTimer = 0;
this.waitForCoroutine = null;
this.enumerator = null;
this.useUnscaledDeltaTime = false;
}
}
export class CoroutineManager extends GlobalManager {
/**
* 标志来跟踪我们何时处于更新循环中。
* 如果在更新循环中启动了一个新的coroutine我们必须将它贴在shouldRunNextFrame列表中以避免在迭代时修改一个数组
*/
public _isInUpdate: boolean;
public _unblockedCoroutines: CoroutineImpl[] = [];
public _shouldRunNextFrame: CoroutineImpl[] = [];
/**
* 将IEnumerator添加到CoroutineManager中
* Coroutine在每一帧调用Update之前被执行
* @param enumerator
*/
public startCoroutine(enumerator: any) {
// 找到或创建一个CoroutineImpl
let coroutine = Pool.obtain<CoroutineImpl>(CoroutineImpl);
coroutine.prepareForUse();
// 设置coroutine并添加它
coroutine.enumerator = enumerator;
let shouldContinueCoroutine = this.tickCoroutine(coroutine);
if (!shouldContinueCoroutine)
return null;
if (this._isInUpdate)
this._shouldRunNextFrame.push(coroutine);
else
this._unblockedCoroutines.push(coroutine);
return coroutine;
}
public update() {
this._isInUpdate = true;
for (let i = 0; i < this._unblockedCoroutines.length; i++) {
let coroutine = this._unblockedCoroutines[i];
if (coroutine.isDone) {
Pool.free(coroutine);
continue;
}
if (coroutine.waitForCoroutine != null) {
if (coroutine.waitForCoroutine.isDone) {
coroutine.waitForCoroutine = null;
} else {
this._shouldRunNextFrame.push(coroutine);
continue;
}
}
if (coroutine.waitTimer > 0) {
// 递减然后再运行下一帧确保用适当的deltaTime递减
coroutine.waitTimer -= coroutine.useUnscaledDeltaTime ? Time.unscaledDeltaTime : Time.deltaTime;
this._shouldRunNextFrame.push(coroutine);
continue;
}
if (this.tickCoroutine(coroutine))
this._shouldRunNextFrame.push(coroutine);
}
let linqCoroutines = new es.List(this._unblockedCoroutines);
linqCoroutines.clear();
linqCoroutines.addRange(this._shouldRunNextFrame);
this._shouldRunNextFrame.length = 0;
this._isInUpdate = false;
}
/**
* 勾选一个coroutine如果该coroutine应该在下一帧继续运行则返回true。本方法会将完成的coroutine放回Pool
* @param coroutine
*/
public tickCoroutine(coroutine: CoroutineImpl) {
let chain = coroutine.enumerator.next();
if (chain.done || coroutine.isDone) {
Pool.free(coroutine);
return false;
}
if (chain.value == null) {
// 下一帧再运行
return true;
}
if (chain.value instanceof WaitForSeconds) {
coroutine.waitTimer = chain.value.waitTime;
return true;
}
if (typeof chain.value == 'number') {
coroutine.waitTimer = chain.value;
return true;
}
if (typeof chain.value == 'string') {
if (chain.value == 'break') {
Pool.free(coroutine);
return false;
}
return true;
}
if (chain.value instanceof CoroutineImpl) {
coroutine.waitForCoroutine = chain.value;
return true;
} else {
return true;
}
}
}
}