新增Coroutine

This commit is contained in:
yhh
2020-12-23 17:14:16 +08:00
parent 8ed3eb24c3
commit fa10d5d4d5
9 changed files with 449 additions and 189 deletions

182
README.md
View File

@@ -3,198 +3,16 @@
## 交流群 ## 交流群
点击链接加入群聊【ecs游戏框架交流】https://jq.qq.com/?_wv=1027&k=29w1Nud6 点击链接加入群聊【ecs游戏框架交流】https://jq.qq.com/?_wv=1027&k=29w1Nud6
## Getting Start
1. 初始化核心
```typescript
// 传入舞台宽高确定屏幕大小
let core = new es.Core(768, 1366);
```
2. 派发核心事件
```typescript
// 必须派发该事件 否则核心内所有更新事件将不会执行 egret写法:
es.Core.emitter.emit(es.CoreEvents.FrameUpdated, egret.getTimer());
// 必须派发该事件 否则核心内所有更新事件将不会执行 laya写法:
// es.Core.emitter.emit(es.CoreEvents.FrameUpdated, Laya.systemTimer.currTimer);
```
3. 创建主场景
```typescript
// 继承es.Scene来确定这是一个场景
class MainScene extends es.Scene {
public initialize(){
// 当场景构造函数执行完成后执行
}
public async onStart() {
// 当场景被激活时执行
}
}
```
4. 创建组件
```typescript
// 敌人组件 继承es.Component确定他是一个组件
// 组件当中不应该含有具体逻辑 只存储数据/属性
class SpawnerComponent extends es.Component {
public cooldown: number = -1;
public minInterval: number = 2;
public maxInterval: number = 60;
public minCount: number = 1;
public maxCount: number = 1;
public enemyType: EnemyType = EnemyType.worm;
public numSpawned: number = 0;
public numAlive: number = 0;
constructor(enemyType: EnemyType) {
super();
this.enemyType = enemyType;
}
}
enum EnemyType {
worm
}
```
5. 创建系统
```typescript
// 每个组件应对应一个系统 系统中负责游戏逻辑
class SpawnerSystem extends es.EntityProcessingSystem {
// 必须实现的构造函数
constructor(matcher: es.Matcher){
super(matcher);
}
// 当满足条件的实体会被派发至这统一进行处理
// 条件在Matcher中进行设置
processEntity(entity: es.Entity){
let spawner = entity.getComponent<component.SpawnerComponent>(component.SpawnerComponent);
if (spawner.numAlive <= 0)
spawner.enabled = true;
if (!spawner.enabled)
return;
if (spawner.cooldown <= -1) {
this.scheduleSpawn(spawner);
console.log("冷却时间已到,进入下一轮刷新 冷却时间:", spawner.cooldown);
spawner.cooldown /= 4;
}
spawner.cooldown -= es.Time.deltaTime;
if (spawner.cooldown <= 0) {
this.scheduleSpawn(spawner);
for (let i = 0; i < RandomUtils.randint(spawner.minCount, spawner.maxCount); i ++) {
console.log("创建敌人", entity.position.x, entity.position.y, spawner.enemyType, entity);
spawner.numSpawned ++;
spawner.numAlive++;
}
if (spawner.numAlive > 0)
spawner.enabled = false;
}
}
private scheduleSpawn(spawner: component.SpawnerComponent) {
spawner.cooldown = RandomUtils.randint(spawner.minInterval, spawner.maxInterval);
}
}
```
6. 创建实体、添加组件、激活实体处理器
```typescript
class MainScene extends es.Scene {
public async onStart() {
// 创建实体
let spawn = this.createEntity("spawn");
// 添加组件
spawn.addComponent(new component.SpawnerComponent(component.EnemyType.worm));
// 添加实体处理
// Matcher.all 代表对带有该组件的实体进行处理
// Matcher.one 代表对至少有一个该组件的实体进行处理
// Matcher.exclude 代表对不带该组件的实体进行处理
this.addEntityProcessor(new system.SpawnerSystem(new es.Matcher().all(component.SpawnerComponent)));
}
}
```
7. 激活场景
```typescript
// 设置MainScene为当前激活的场景
es.Core.scene = new MainScene();
```
### 示例地址 ### 示例地址
- [laya-demo](https://github.com/esengine/ecs-laya-demo) - [laya-demo](https://github.com/esengine/ecs-laya-demo)
- [egret-demo](https://github.com/esengine/ecs-egret-demo) - [egret-demo](https://github.com/esengine/ecs-egret-demo)
- [ecs-modern-egret](https://github.com/esengine/ecs-modern-egret)
![GIF](https://github.com/esengine/ecs-framework/blob/master/screenshot/GIF.gif)
## 扩展库 ## 扩展库
- [基于ecs-framework开发的astar/BreadthFirst/Dijkstra/GOAP目标导向计划 路径寻找库](https://github.com/esengine/ecs-astar) - [基于ecs-framework开发的astar/BreadthFirst/Dijkstra/GOAP目标导向计划 路径寻找库](https://github.com/esengine/ecs-astar)
- [基于ecs-framework开发的AIBehaviourTree、UtilityAI系统](https://github.com/esengine/BehaviourTree-ai)) - [基于ecs-framework开发的AIBehaviourTree、UtilityAI系统](https://github.com/esengine/BehaviourTree-ai))
## 版本计划功能
- [x] 简易ECS框架
- [x] 组件列表
- [x] 碰撞组件
- [x] 移动组件
- [x] 组件池
- [x] 基础碰撞组件(矩形、圆形、多边形碰撞)
- [x] 场景组件
- [x] 系统列表
- [x] 被动系统
- [x] 协调系统
- [x] 实体系统
- [x] 实体解析系统
- [x] 扩展库
- [x] string扩展
- [x] time扩展
- [x] [array扩展Extension](https://github.com/esengine/egret-framework/wiki/Array-%E6%89%A9%E5%B1%95%E8%AF%B4%E6%98%8E)
- [x] base64扩展
- [x] Stopwatch计数器
- [x] List池对象
- [x] Emitter事件发射器
- [x] Random随机类帮助
- [x] Rectangle矩形帮助类
- [x] Vector2向量帮助类
- [x] 全局管理器
- [x] 向量集Bitset
- [x] 图形帮助
- [x] 场景过渡
- [x] 场景渲染器
- [x] 常用碰撞检测
- [x] 数学库
- [x] 矩形类Rectangle
- [x] 简易2D矩阵类Matrix2D
- [x] 简易2d 向量类Vector2
- [x] 数学扩展库MathHelper
- [x] 掩码实用类Flags
- [x] 贝塞尔曲线Bezier
- [x] 物理系统(简易)
- [x] Collision碰撞检测
- [x] ColliderTrigger帮助
- [x] [Ray2D射线检测](https://github.com/esengine/egret-framework/wiki/Ray2D-2D%E5%B0%84%E7%BA%BF)
- [x] ShapeCollision 多种形状检测
- [x] RealtimeCollisions 实时碰撞检测
- [x] SpatialHash 网格检测
- [x] 事件处理器
## 关于用ecs框架typescript/javascript ## 关于用ecs框架typescript/javascript
ecs 是功能强大的实体组件系统。typescript与其他语言不同因此我对ecs的设计尽可能的支持typescript特性。虽然ecs拥有标准实体组件系统但在细节上有很大不同。创建标准ecs通常处于原始速度、缓存位置和其他性能原因。使用typescript我们没有struct因为没有必要匹配标准实体组件系统的设计方式因为我们对内存布局没有那种控制。 ecs 是功能强大的实体组件系统。typescript与其他语言不同因此我对ecs的设计尽可能的支持typescript特性。虽然ecs拥有标准实体组件系统但在细节上有很大不同。创建标准ecs通常处于原始速度、缓存位置和其他性能原因。使用typescript我们没有struct因为没有必要匹配标准实体组件系统的设计方式因为我们对内存布局没有那种控制。

View File

@@ -96,6 +96,7 @@ declare module es {
* 全局访问系统 * 全局访问系统
*/ */
_globalManagers: GlobalManager[]; _globalManagers: GlobalManager[];
_coroutineManager: CoroutineManager;
_timerManager: TimerManager; _timerManager: TimerManager;
width: number; width: number;
height: number; height: number;
@@ -133,6 +134,12 @@ declare module es {
* @param type * @param type
*/ */
static getGlobalManager<T extends es.GlobalManager>(type: any): T; static getGlobalManager<T extends es.GlobalManager>(type: any): T;
/**
* 启动一个coroutine。Coroutine可以将number延时几秒或延时到其他startCoroutine.Yielding
* null将使coroutine在下一帧被执行。
* @param enumerator
*/
static startCoroutine(enumerator: any): ICoroutine;
/** /**
* 调度一个一次性或重复的计时器,该计时器将调用已传递的动作 * 调度一个一次性或重复的计时器,该计时器将调用已传递的动作
* @param timeInSeconds * @param timeInSeconds
@@ -3497,6 +3504,77 @@ declare module es {
areEqual(value1: T, value2: T): boolean; areEqual(value1: T, value2: T): boolean;
} }
} }
declare module es {
/**
* startCoroutine返回的接口它提供了中途停止coroutine的能力。
*/
interface ICoroutine {
/**
* 停止Coroutine
*/
stop(): any;
/**
* 设置Coroutine是否应该使用deltaTime或unscaledDeltaTime进行计时
* @param useUnscaledDeltaTime
*/
setUseUnscaledDeltaTime(useUnscaledDeltaTime: boolean): ICoroutine;
}
class Coroutine {
/**
* 导致Coroutine在指定的时间内暂停。在Coroutine.waitForSeconds的基础上在Coroutine中使用Yield
* @param seconds
*/
static waitForSeconds(seconds: number): WaitForSeconds;
}
/**
* 帮助类用于当一个coroutine想要暂停一段时间时。返回Coroutine.waitForSeconds返回其中一个
*/
class WaitForSeconds {
static waiter: WaitForSeconds;
waitTime: number;
wait(seconds: number): WaitForSeconds;
}
}
declare module es {
/**
* CoroutineManager用于隐藏Coroutine所需数据的内部类
*/
class CoroutineImpl implements ICoroutine, IPoolable {
enumerator: any;
/**
* 每当产生一个延迟它就会被添加到跟踪延迟的waitTimer中
*/
waitTimer: number;
isDone: boolean;
waitForCoroutine: CoroutineImpl;
useUnscaledDeltaTime: boolean;
stop(): void;
setUseUnscaledDeltaTime(useUnscaledDeltaTime: boolean): this;
prepareForUse(): void;
reset(): void;
}
class CoroutineManager extends GlobalManager {
/**
* 标志来跟踪我们何时处于更新循环中。
* 如果在更新循环中启动了一个新的coroutine我们必须将它贴在shouldRunNextFrame列表中以避免在迭代时修改一个数组
*/
_isInUpdate: boolean;
_unblockedCoroutines: CoroutineImpl[];
_shouldRunNextFrame: CoroutineImpl[];
/**
* 将IEnumerator添加到CoroutineManager中
* Coroutine在每一帧调用Update之前被执行
* @param enumerator
*/
startCoroutine(enumerator: any): CoroutineImpl;
update(): void;
/**
* 勾选一个coroutine如果该coroutine应该在下一帧继续运行则返回true。本方法会将完成的coroutine放回Pool
* @param coroutine
*/
tickCoroutine(coroutine: CoroutineImpl): boolean;
}
}
declare class ArrayUtils { declare class ArrayUtils {
/** /**
* 执行冒泡排序 * 执行冒泡排序

View File

@@ -197,6 +197,7 @@ var es;
* 全局访问系统 * 全局访问系统
*/ */
this._globalManagers = []; this._globalManagers = [];
this._coroutineManager = new es.CoroutineManager();
this._timerManager = new es.TimerManager(); this._timerManager = new es.TimerManager();
this._frameCounterElapsedTime = 0; this._frameCounterElapsedTime = 0;
this._frameCounter = 0; this._frameCounter = 0;
@@ -206,6 +207,7 @@ var es;
Core._instance = this; Core._instance = this;
Core.emitter = new es.Emitter(); Core.emitter = new es.Emitter();
Core.emitter.addObserver(es.CoreEvents.FrameUpdated, this.update, this); Core.emitter.addObserver(es.CoreEvents.FrameUpdated, this.update, this);
Core.registerGlobalManager(this._coroutineManager);
Core.registerGlobalManager(this._timerManager); Core.registerGlobalManager(this._timerManager);
Core.entitySystemsEnabled = enableEntitySystems; Core.entitySystemsEnabled = enableEntitySystems;
this.initialize(); this.initialize();
@@ -278,6 +280,14 @@ var es;
} }
return null; return null;
}; };
/**
* 启动一个coroutine。Coroutine可以将number延时几秒或延时到其他startCoroutine.Yielding
* null将使coroutine在下一帧被执行。
* @param enumerator
*/
Core.startCoroutine = function (enumerator) {
return this._instance._coroutineManager.startCoroutine(enumerator);
};
/** /**
* 调度一个一次性或重复的计时器,该计时器将调用已传递的动作 * 调度一个一次性或重复的计时器,该计时器将调用已传递的动作
* @param timeInSeconds * @param timeInSeconds
@@ -8827,6 +8837,164 @@ var es;
}(Set)); }(Set));
es.HashSet = HashSet; es.HashSet = HashSet;
})(es || (es = {})); })(es || (es = {}));
var es;
(function (es) {
var Coroutine = /** @class */ (function () {
function Coroutine() {
}
/**
* 导致Coroutine在指定的时间内暂停。在Coroutine.waitForSeconds的基础上在Coroutine中使用Yield
* @param seconds
*/
Coroutine.waitForSeconds = function (seconds) {
return WaitForSeconds.waiter.wait(seconds);
};
return Coroutine;
}());
es.Coroutine = Coroutine;
/**
* 帮助类用于当一个coroutine想要暂停一段时间时。返回Coroutine.waitForSeconds返回其中一个
*/
var WaitForSeconds = /** @class */ (function () {
function WaitForSeconds() {
this.waitTime = 0;
}
WaitForSeconds.prototype.wait = function (seconds) {
WaitForSeconds.waiter.waitTime = seconds;
return WaitForSeconds.waiter;
};
WaitForSeconds.waiter = new WaitForSeconds();
return WaitForSeconds;
}());
es.WaitForSeconds = WaitForSeconds;
})(es || (es = {}));
var es;
(function (es) {
/**
* CoroutineManager用于隐藏Coroutine所需数据的内部类
*/
var CoroutineImpl = /** @class */ (function () {
function CoroutineImpl() {
/**
* 每当产生一个延迟它就会被添加到跟踪延迟的waitTimer中
*/
this.waitTimer = 0;
this.useUnscaledDeltaTime = false;
}
CoroutineImpl.prototype.stop = function () {
this.isDone = true;
};
CoroutineImpl.prototype.setUseUnscaledDeltaTime = function (useUnscaledDeltaTime) {
this.useUnscaledDeltaTime = useUnscaledDeltaTime;
return this;
};
CoroutineImpl.prototype.prepareForUse = function () {
this.isDone = false;
};
CoroutineImpl.prototype.reset = function () {
this.isDone = true;
this.waitTimer = 0;
this.waitForCoroutine = null;
this.enumerator = null;
this.useUnscaledDeltaTime = false;
};
return CoroutineImpl;
}());
es.CoroutineImpl = CoroutineImpl;
var CoroutineManager = /** @class */ (function (_super) {
__extends(CoroutineManager, _super);
function CoroutineManager() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._unblockedCoroutines = [];
_this._shouldRunNextFrame = [];
return _this;
}
/**
* 将IEnumerator添加到CoroutineManager中
* Coroutine在每一帧调用Update之前被执行
* @param enumerator
*/
CoroutineManager.prototype.startCoroutine = function (enumerator) {
// 找到或创建一个CoroutineImpl
var coroutine = es.Pool.obtain(CoroutineImpl);
coroutine.prepareForUse();
// 设置coroutine并添加它
coroutine.enumerator = enumerator;
var shouldContinueCoroutine = this.tickCoroutine(coroutine);
if (!shouldContinueCoroutine)
return null;
if (this._isInUpdate)
this._shouldRunNextFrame.push(coroutine);
else
this._unblockedCoroutines.push(coroutine);
return coroutine;
};
CoroutineManager.prototype.update = function () {
this._isInUpdate = true;
for (var i = 0; i < this._unblockedCoroutines.length; i++) {
var coroutine = this._unblockedCoroutines[i];
if (coroutine.isDone) {
es.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 ? es.Time.unscaledDeltaTime : es.Time.deltaTime;
this._shouldRunNextFrame.push(coroutine);
continue;
}
if (this.tickCoroutine(coroutine))
this._shouldRunNextFrame.push(coroutine);
}
var linqCoroutines = new linq.List(this._unblockedCoroutines);
linqCoroutines.clear();
linqCoroutines.addRange(this._shouldRunNextFrame);
this._shouldRunNextFrame.length = 0;
this._isInUpdate = false;
};
/**
* 勾选一个coroutine如果该coroutine应该在下一帧继续运行则返回true。本方法会将完成的coroutine放回Pool
* @param coroutine
*/
CoroutineManager.prototype.tickCoroutine = function (coroutine) {
var chain = coroutine.enumerator.next();
if (chain.done || coroutine.isDone) {
es.Pool.free(coroutine);
return false;
}
if (chain.value == null) {
// 下一帧再运行
return true;
}
if (chain.value instanceof es.WaitForSeconds) {
coroutine.waitTimer = chain.value.waitTime;
return true;
}
if (typeof chain.value == 'number') {
coroutine.waitTimer = chain.value;
return true;
}
if (chain.value instanceof CoroutineImpl) {
coroutine.waitForCoroutine = chain.value;
return true;
}
else {
return true;
}
};
return CoroutineManager;
}(es.GlobalManager));
es.CoroutineManager = CoroutineManager;
})(es || (es = {}));
var ArrayUtils = /** @class */ (function () { var ArrayUtils = /** @class */ (function () {
function ArrayUtils() { function ArrayUtils() {
} }

File diff suppressed because one or more lines are too long

View File

@@ -33,6 +33,7 @@ module es {
* 全局访问系统 * 全局访问系统
*/ */
public _globalManagers: GlobalManager[] = []; public _globalManagers: GlobalManager[] = [];
public _coroutineManager: CoroutineManager = new CoroutineManager();
public _timerManager: TimerManager = new TimerManager(); public _timerManager: TimerManager = new TimerManager();
public width: number; public width: number;
public height: number; public height: number;
@@ -45,6 +46,7 @@ module es {
Core.emitter = new Emitter<CoreEvents>(); Core.emitter = new Emitter<CoreEvents>();
Core.emitter.addObserver(CoreEvents.FrameUpdated, this.update, this); Core.emitter.addObserver(CoreEvents.FrameUpdated, this.update, this);
Core.registerGlobalManager(this._coroutineManager);
Core.registerGlobalManager(this._timerManager); Core.registerGlobalManager(this._timerManager);
Core.entitySystemsEnabled = enableEntitySystems; Core.entitySystemsEnabled = enableEntitySystems;
@@ -123,6 +125,15 @@ module es {
return null; return null;
} }
/**
* 启动一个coroutine。Coroutine可以将number延时几秒或延时到其他startCoroutine.Yielding
* null将使coroutine在下一帧被执行。
* @param enumerator
*/
public static startCoroutine(enumerator): ICoroutine {
return this._instance._coroutineManager.startCoroutine(enumerator);
}
/** /**
* 调度一个一次性或重复的计时器,该计时器将调用已传递的动作 * 调度一个一次性或重复的计时器,该计时器将调用已传递的动作
* @param timeInSeconds * @param timeInSeconds
@@ -130,7 +141,7 @@ module es {
* @param context * @param context
* @param onTime * @param onTime
*/ */
public static schedule(timeInSeconds: number, repeats: boolean = false, context: any = null, onTime: (timer: ITimer)=>void){ public static schedule(timeInSeconds: number, repeats: boolean = false, context: any = null, onTime: (timer: ITimer) => void) {
return this._instance._timerManager.schedule(timeInSeconds, repeats, context, onTime); return this._instance._timerManager.schedule(timeInSeconds, repeats, context, onTime);
} }
@@ -139,7 +150,7 @@ module es {
} }
public startDebugDraw() { public startDebugDraw() {
this._frameCounter ++; this._frameCounter++;
this._frameCounterElapsedTime += Time.deltaTime; this._frameCounterElapsedTime += Time.deltaTime;
if (this._frameCounterElapsedTime >= 1) { if (this._frameCounterElapsedTime >= 1) {
let memoryInfo = window.performance["memory"]; let memoryInfo = window.performance["memory"];
@@ -165,7 +176,7 @@ module es {
*/ */
protected onGraphicsDeviceReset() { protected onGraphicsDeviceReset() {
// 我们用这些来避免垃圾事件的发生 // 我们用这些来避免垃圾事件的发生
if (this._graphicsDeviceChangeTimer != null){ if (this._graphicsDeviceChangeTimer != null) {
this._graphicsDeviceChangeTimer.reset(); this._graphicsDeviceChangeTimer.reset();
} else { } else {
this._graphicsDeviceChangeTimer = Core.schedule(0.05, false, this, t => { this._graphicsDeviceChangeTimer = Core.schedule(0.05, false, this, t => {

View File

@@ -0,0 +1,39 @@
module es {
/**
* startCoroutine返回的接口它提供了中途停止coroutine的能力。
*/
export interface ICoroutine {
/**
* 停止Coroutine
*/
stop();
/**
* 设置Coroutine是否应该使用deltaTime或unscaledDeltaTime进行计时
* @param useUnscaledDeltaTime
*/
setUseUnscaledDeltaTime(useUnscaledDeltaTime: boolean): ICoroutine;
}
export class Coroutine {
/**
* 导致Coroutine在指定的时间内暂停。在Coroutine.waitForSeconds的基础上在Coroutine中使用Yield
* @param seconds
*/
public static waitForSeconds(seconds: number) {
return WaitForSeconds.waiter.wait(seconds);
}
}
/**
* 帮助类用于当一个coroutine想要暂停一段时间时。返回Coroutine.waitForSeconds返回其中一个
*/
export class WaitForSeconds {
public static waiter: WaitForSeconds = new WaitForSeconds();
public waitTime: number = 0;
public wait(seconds: number): WaitForSeconds {
WaitForSeconds.waiter.waitTime = seconds;
return WaitForSeconds.waiter;
}
}
}

View File

@@ -0,0 +1,146 @@
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 linq.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 (chain.value instanceof CoroutineImpl) {
coroutine.waitForCoroutine = chain.value;
return true;
} else {
return true;
}
}
}
}