[汪汪队] 动态功能入口管理器(子游戏加载)

对应小游戏来说,新用户加载速度越快越好,大家一般会把各个功能模块分成不同的包,为了便于管理这些入口和功能,我花了几分钟写了个功能入口管理器,具有一下功能:

  1. 用于统一管理各个功能入口
  2. 自动加载关联资源
  3. 在入口开启和关闭的情况下,主动通知
  4. 功能足够简单,所以易于扩展 :joy:,可以自己增加资源下载进度,用来做如子游戏的加载进度等

以下是关键代码:

  • 资源加载和消息通知部分就改成自己的方案就行啦!
  • 不用的地方自己删除
import { EventCenter } from "../core/utils/EventCenter";
import FGUIExt from "../core/utils/FGUIExt";
import { ResManager } from "./ResManager";

type FunctionEnterChecker = ()=>boolean;
type FunctionEnterEnter = ()=>void;

type FunctionEnterConfig = {
    resPkg?: string,
    uiPkg?: string,
    checker: FunctionEnterChecker,
    enter?: FunctionEnterEnter,
    exit?: FunctionEnterEnter,
    alwaysCheck?: boolean,
}

export class FunctionEnter {
    private _name: string;
    private _config: FunctionEnterConfig;
    private _thisObj: any;
    private _isEntered = false;

    public get config(): FunctionEnterConfig {
        return this._config;
    }

    public get name(): string {
        return this._name;
    }

    constructor(name: string, config: FunctionEnterConfig, thisObj?: any) {
        this._name = name;
        this._config = config;
        this._thisObj = thisObj;
    }

    check(): boolean {
        let ret = this.config.checker();
        if(this._isEntered != ret) {
            if(ret) {
                this._enterFunc();
            }else{
                if(this._isEntered && this.config.exit) {
                    this.config.exit.call(this._thisObj);
                    this._isEntered = false;

                    EventCenter.I.emit(FunctionEnterManager.FUNCTION_CLOSE, this.name);
                }            
            }
        }
        return ret;
    }

    private async _enterFunc() {
        if(this._config.resPkg || this._config.uiPkg) {
            EventCenter.I.emit(FunctionEnterManager.FUNCTION_LOADING, this.name, 0);

            if(this._config.resPkg) {
                await ResManager.loadResBundle(this.config.resPkg);

                if(this._config.uiPkg) {
                    await FGUIExt.preloadPackage(this.config.resPkg, this.config.uiPkg);
                }
            }
        }
        if(this.config.enter) {
            this.config.enter.call(this._thisObj);
        }
        this._isEntered = true;

        EventCenter.I.emit(FunctionEnterManager.FUNCTION_OPEND, this.name);
    }
}

/**
 * 功能入口管理器
 */
export class FunctionEnterManager {
    static FUNCTION_LOADING = 'FUNCTION_LOADING';//功能加载中
    static FUNCTION_OPEND = 'FUNCTION_OPEND';//功能开启
    static FUNCTION_CLOSE = 'FUNCTION_CLOSE';//功能关闭

    private static _instance: FunctionEnterManager;
    static get inst(): FunctionEnterManager {
        if(!this._instance) {
            this._instance = new FunctionEnterManager();
        }
        return this._instance;
    }

    private _enterList: FunctionEnter[] = [];
    public add(name: string, config: FunctionEnterConfig, thisObj?: any) {
        let func = new FunctionEnter(name, config, thisObj);
        this._enterList.push(func);
    }

    public remove(name: string) {
        for(let i=this._enterList.length-1; i>=0; i--) {
            let func = this._enterList[i];
            if(func.name == name) {
                this._enterList.splice(i, 1);
            }
        }
    }

    public update(dt: number) {
        for(let i=this._enterList.length-1; i>=0; i--) {
            let func = this._enterList[i];
            if(func.check() && !func.config.alwaysCheck) {
                this._enterList.splice(i, 1);
            }
        }
    }    
}

用法:

  • 找个地方调用update
  • 在需要的地方注册相关功能入口,自己给入口开启条件,在开启入口后写上自己的相关逻辑

类似这样:
image

然后,入口的按钮就会在满足条件,且资源加载完毕后显示出来!!

望轻喷!!!

为什么要通过 update 不断的 check,完全没必要呀?基于事件管理,减少计算。

不带上TGX了?

事件哪儿来的?开不开也就是一个标记的事情,没啥计算量,主要是方便做轻量化,整合所有功能

哦哦,这是TGX最小化实现