新增 CoroutineManager 协同程序
This commit is contained in:
@@ -66,7 +66,7 @@ module es {
|
||||
this._logs[i] = new FrameLog();
|
||||
|
||||
this.sampleFrames = this.targetSampleFrames = 1;
|
||||
this.width = Core.graphicsDevice.viewport.width * 0.8;
|
||||
this.width = Math.floor(Core.graphicsDevice.viewport.width * 0.8);
|
||||
|
||||
es.Core.emitter.addObserver(CoreEvents.GraphicsDeviceReset, this.onGraphicsDeviceReset, this);
|
||||
this.onGraphicsDeviceReset();
|
||||
@@ -269,7 +269,7 @@ module es {
|
||||
|
||||
if (Math.max(this._frameAdjust) > TimeRuler.autoAdjustDelay) {
|
||||
this.sampleFrames = Math.min(TimeRuler.maxSampleFrames, this.sampleFrames);
|
||||
this.sampleFrames = Math.max(this.targetSampleFrames, (maxTime / frameSpan) + 1);
|
||||
this.sampleFrames = Math.max(this.targetSampleFrames, Math.floor(maxTime / frameSpan) + 1);
|
||||
|
||||
this._frameAdjust = 0;
|
||||
}
|
||||
|
||||
38
source/src/Utils/Coroutines/Coroutine.ts
Normal file
38
source/src/Utils/Coroutines/Coroutine.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
module es {
|
||||
/**
|
||||
* startCoroutine返回的接口,提供了在执行中停止协同程序的能力
|
||||
*/
|
||||
export interface ICoroutine {
|
||||
/**
|
||||
* 停止协同程序
|
||||
*/
|
||||
stop();
|
||||
|
||||
/**
|
||||
* 设置协程应该使用时间增量还是使用非缩放时间增量来计时
|
||||
* @param useUnscaledDeltaTime
|
||||
*/
|
||||
setUseUnscaledDeltaTime(useUnscaledDeltaTime): ICoroutine;
|
||||
}
|
||||
|
||||
export class Coroutine {
|
||||
public static waitForSeconds(seconds: number){
|
||||
return WaitForSeconds.waiter.wait(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 协作程序需要暂停一段时间时的助手类。
|
||||
* 返回协同程序。
|
||||
* waitForSeconds返回number。
|
||||
*/
|
||||
export class WaitForSeconds {
|
||||
public static waiter: WaitForSeconds = new WaitForSeconds();
|
||||
public waitTime: number;
|
||||
|
||||
public wait(seconds: number): WaitForSeconds {
|
||||
WaitForSeconds.waiter.waitTime = seconds;
|
||||
return WaitForSeconds.waiter;
|
||||
}
|
||||
}
|
||||
}
|
||||
159
source/src/Utils/Coroutines/CoroutineManager.ts
Normal file
159
source/src/Utils/Coroutines/CoroutineManager.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
module es {
|
||||
/**
|
||||
* CoroutineManager使用的内部类,用于隐藏协同程序所需的数据
|
||||
*/
|
||||
export class CoroutineImpl implements ICoroutine, IPoolable {
|
||||
public enumerator: IEnumerator;
|
||||
/**
|
||||
* 每当产生延迟时,它就被添加到跟踪延迟的waitTimer中
|
||||
*/
|
||||
public waitTimer: number;
|
||||
public isDone: boolean;
|
||||
public waitForCoroutine: CoroutineImpl;
|
||||
public useUnscaledDeltaTime: boolean = false;
|
||||
|
||||
public stop(){
|
||||
this.isDone = true;
|
||||
}
|
||||
|
||||
public setUseUnscaledDeltaTime(useUnscaledDeltaTime): es.ICoroutine {
|
||||
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 interface IEnumerator {
|
||||
current: any;
|
||||
moveNext(): boolean;
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本CoroutineManager。协同程序可以做以下事情:
|
||||
* - return null(在下一帧继续执行)
|
||||
* - return Coroutine.waitForSeconds(3)。等待3秒(延时3秒后再次执行)
|
||||
* - return startCoroutine(another())(在再次执行之前等待另一个协程)
|
||||
*/
|
||||
export class CoroutineManager extends GlobalManager {
|
||||
/**
|
||||
* 标记来跟踪何时处于更新循环中。
|
||||
* 如果一个新的协程在更新循环期间启动,我们必须将其插入到shouldRunNextFrame列表中,以避免在迭代时修改列表。
|
||||
*/
|
||||
public _isInUpdate: boolean;
|
||||
|
||||
public _unblockedCoroutines: CoroutineImpl[] = [];
|
||||
public _shouldRunNextFrame: CoroutineImpl[] = [];
|
||||
|
||||
/**
|
||||
* 将i枚举器添加到CoroutineManager。协程在每一帧调用更新之前被执行。
|
||||
* @param enumerator
|
||||
*/
|
||||
public startCoroutine(enumerator: IEnumerator) {
|
||||
// 查找或创建CoroutineImpl
|
||||
let coroutine = Pool.obtain<CoroutineImpl>(CoroutineImpl);
|
||||
coroutine.prepareForuse();
|
||||
|
||||
// 设置协程并添加它
|
||||
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<CoroutineImpl>(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);
|
||||
}
|
||||
|
||||
this._unblockedCoroutines.length = 0;
|
||||
this._unblockedCoroutines.concat(this._shouldRunNextFrame);
|
||||
this._shouldRunNextFrame.length = 0;
|
||||
|
||||
this._isInUpdate = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果协同程序在下一帧继续运行,则返回true。此方法将把完成的协程放回池中!
|
||||
* @param coroutine
|
||||
*/
|
||||
public tickCoroutine(coroutine: CoroutineImpl){
|
||||
// 这个协同程序已经完成了
|
||||
if (!coroutine.enumerator.moveNext() || coroutine.isDone){
|
||||
Pool.free<CoroutineImpl>(coroutine);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (coroutine.enumerator.current == null){
|
||||
// 再运行下一帧
|
||||
return true;
|
||||
}
|
||||
|
||||
if (coroutine.enumerator.current instanceof WaitForSeconds){
|
||||
coroutine.waitTimer = (coroutine.enumerator.current as WaitForSeconds).waitTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (coroutine.enumerator.current instanceof Number){
|
||||
console.warn("协同程序检查返回一个Number类型,请不要在生产环境使用");
|
||||
coroutine.waitTimer = Number(coroutine.enumerator.current);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (coroutine.enumerator.current instanceof CoroutineImpl){
|
||||
coroutine.waitForCoroutine = coroutine.enumerator.current as CoroutineImpl;
|
||||
return true;
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
source/src/Utils/Pool.ts
Normal file
67
source/src/Utils/Pool.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
module es {
|
||||
/**
|
||||
* 用于池任何对象
|
||||
*/
|
||||
export class Pool<T> {
|
||||
private static _objectQueue = new Array(10);
|
||||
|
||||
/**
|
||||
* 预热缓存,使用最大的cacheCount对象填充缓存
|
||||
* @param type
|
||||
* @param cacheCount
|
||||
*/
|
||||
public static warmCache(type: any, cacheCount: number){
|
||||
cacheCount -= this._objectQueue.length;
|
||||
if (cacheCount > 0) {
|
||||
for (let i = 0; i < cacheCount; i++) {
|
||||
this._objectQueue.unshift(new type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将缓存修剪为cacheCount项目
|
||||
* @param cacheCount
|
||||
*/
|
||||
public static trimCache(cacheCount: number){
|
||||
while (cacheCount > this._objectQueue.length)
|
||||
this._objectQueue.shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
*/
|
||||
public static clearCache() {
|
||||
this._objectQueue.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果可以的话,从堆栈中弹出一个项
|
||||
*/
|
||||
public static obtain<T>(type: any): T {
|
||||
if (this._objectQueue.length > 0)
|
||||
return this._objectQueue.shift();
|
||||
|
||||
return new type() as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将项推回堆栈
|
||||
* @param obj
|
||||
*/
|
||||
public static free<T>(obj: T) {
|
||||
this._objectQueue.unshift(obj);
|
||||
|
||||
if (egret.is(obj, "IPoolable")){
|
||||
obj["reset"]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPoolable {
|
||||
/**
|
||||
* 重置对象以供重用。对象引用应该为空,字段可以设置为默认值
|
||||
*/
|
||||
reset();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user