123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- import { Component, Director, director, isValid } from 'cc';
- declare type GeneratorFunc = (...args: any[]) => Generator<any, any, any>
- declare type GeneratorRecord = { generator: Generator<any, any, any>, gfunc?: GeneratorFunc, comp?: Component, waiter?: IWaiter };
- interface IWaiter {
- isOver(dt: number): boolean;
- }
- class WaitForSecond implements IWaiter {
- private _endTime: number = 0;
- private _currTime: number = 0;
- constructor(endTime: number) {
- this._endTime = endTime;
- }
- isOver(dt: number) {
- this._currTime += dt;
- return this._currTime >= this._endTime;
- }
- }
- class WaitForFrame implements IWaiter {
- private _frameCount: number = 0;
- private _frame: number = 0;
- constructor(frameCount: number) {
- this._frameCount = frameCount;
- }
- isOver(dt: number) {
- return this._frame++ >= this._frameCount;
- }
- }
- export default class Coroutine {
- private static _instance: Coroutine = null;
- static get instance() {
- if (Coroutine._instance == null) {
- Coroutine._instance = new Coroutine();
- }
- return Coroutine._instance;
- }
- /**等待多少秒 */
- static createWaitForSecond(sec: number) {
- return new WaitForSecond(sec);
- }
- /**等待多少帧 */
- static createWaitForFrame(frameCount: number) {
- return new WaitForFrame(frameCount);
- }
- private _mapCoroutine: Map<any, GeneratorRecord[]> = new Map();
- private _getTimmer: () => number = null;
- private _lastTime: number = 0;
- private constructor() {
- if (typeof window?.performance?.now !== 'function') {
- this._getTimmer = () => {
- return new Date().getTime();
- }
- } else {
- this._lastTime = window.performance.now();
- this._getTimmer = () => window.performance.now();
- }
- }
- /**@summary start coroutiine
- * @param component cc component
- * @param func generator func or string
- * @param args your funcion params
- */
- start(component: Component, func: GeneratorFunc | string, ...args: any[]) {
- if (!(component instanceof Component)) {
- throw Error('component must a component');
- }
- const mapData: GeneratorRecord = {
- generator: null,
- comp: component
- };
- if (typeof func === 'string') {
- const gf: GeneratorFunc = (<any>component)[func];
- const generator = gf.call(component, ...args);
- if (typeof generator?.next === 'function') {
- mapData.generator = generator;
- mapData.gfunc = (<any>component)[func];
- } else {
- throw Error(func + ' is not a GeneratorFunction !!!');
- }
- } else {
- mapData.gfunc = func;
- mapData.generator = func.call(component, ...args);
- }
- const _processCount = this._mapCoroutine.size;
- if (mapData.generator) {
- const list = this._mapCoroutine.get(component);
- if (!list) {
- this._mapCoroutine.set(component, [mapData]);
- } else {
- list.push(mapData);
- }
- }
- if (_processCount == 0 && this._mapCoroutine.size > 0) {
- this._lastTime = this._getTimmer();
- director.on(Director.EVENT_AFTER_UPDATE, this._update, this);
- }
- }
- /**@summary stop coroutiine
- * @param component cc component
- * @param func if no input, that will stop all coroutine of component;
- */
- stop(component: Component, func?: GeneratorFunc | string) {
- if (!func) {
- this._mapCoroutine.delete(component);
- } else {
- const list = this._mapCoroutine.get(component);
- if (!list) return;
- let deleteIds: number[] = [];
- for (let i = 0; i < list.length; ++i) {
- if (!list[i]) {
- list[i] = null;
- deleteIds.push(i);
- }
- else if (typeof func === 'string' && list[i].gfunc === (<any>component)[func]) {
- list[i] = null;
- deleteIds.push(i);
- } else if (list[i].gfunc == func) {
- list[i] = null;
- deleteIds.push(i);
- }
- }
- if (deleteIds.length >= list.length) {
- this._mapCoroutine.delete(component);
- return;
- } else if (deleteIds.length >= 2) {
- this._mapCoroutine.set(component, list.filter((e) => !!e));
- } else if (deleteIds.length == 1) {
- list.splice(deleteIds[0], 1);
- }
- }
- }
- private _update() {
- const dt = (this._getTimmer() - this._lastTime) / 1000;
- this._mapCoroutine.forEach((gr, k) => {
- let deleteIds: number[] = [];
- let count = gr.length;
- for (let i = 0; i < count; ++i) {
- if (!(gr && isValid(gr[i]?.comp?.node, true))) {
- deleteIds.push(i);
- gr[i] = null;
- } else {
- if (gr[i].waiter) {
- if (!gr[i].waiter.isOver(dt)) {
- continue;
- }
- }
- const it = gr[i].generator.next();
- if (it.value instanceof WaitForSecond) {
- if (!it.value.isOver(dt)) {
- gr[i].waiter = it.value;
- continue;
- }
- } else if (it.value instanceof WaitForFrame) {
- gr[i].waiter = it.value;
- if (!it.value.isOver(dt)) {
- gr[i].waiter = it.value;
- continue;
- }
- }
- if (it.done) {
- deleteIds.push(i);
- gr[i] = null;
- }
- }
- }
- if (deleteIds.length >= gr.length) {
- this._mapCoroutine.delete(k);
- return;
- } else if (deleteIds.length >= 2) {
- this._mapCoroutine.set(k, gr.filter((e) => !!e));
- } else if (deleteIds.length == 1) {
- gr.splice(deleteIds[0], 1);
- }
- });
- this._lastTime = this._getTimmer();
- this._mapCoroutine.size == 0 && director.off(Director.EVENT_AFTER_UPDATE, this._update, this);
- }
- }
|