From b4ea586d1a21c8093f09b2801465214c02ed190a Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 17:19:57 +0800 Subject: [PATCH] =?UTF-8?q?Gui=E6=A1=86=E6=9E=B6=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=80=9A=E8=BF=87gui.register=E6=B3=A8=E5=86=8C=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/Gui.ts | 31 +++++++ assets/core/gui/Gui.ts.meta | 9 ++ assets/core/gui/layer/LayerEnum.ts | 2 +- assets/core/gui/layer/LayerManager.ts | 21 +++-- assets/core/gui/layer/LayerUIElement.ts | 10 ++- assets/libs/ecs/ECS.ts | 6 +- assets/libs/ecs/ECSComp.ts | 8 +- assets/libs/ecs/ECSEntity.ts | 5 +- assets/module/common/CCComp.ts | 16 ++-- assets/module/common/CCVMParentComp.ts | 14 +++- assets/module/common/GameComponent.ts | 18 ++++ assets/module/common/ModuleUtil.ts | 105 ++++++++++++++++++++---- assets/module/config/GameConfig.ts | 1 + 13 files changed, 203 insertions(+), 43 deletions(-) create mode 100644 assets/core/gui/Gui.ts create mode 100644 assets/core/gui/Gui.ts.meta diff --git a/assets/core/gui/Gui.ts b/assets/core/gui/Gui.ts new file mode 100644 index 0000000..5ffdece --- /dev/null +++ b/assets/core/gui/Gui.ts @@ -0,0 +1,31 @@ +import { UIConfigMap } from "./layer/LayerEnum"; +import { UIConfig } from "./layer/UIConfig"; + +var configs: UIConfigMap = {}; + +export namespace gui { + /** 注册界面组件 */ + export function register(key: string, config: UIConfig) { + return function (ctor: any) { + ctor.oopsGuiKey = key; + setConfig(key, config); + }; + } + + /** 获取界面组件配置 */ + export function getConfig(key: string) { + return configs[key]; + } + + /** 获取界面组件配置 */ + export function setConfig(key: string, config: UIConfig) { + configs[key] = config; + } + + /** 获取所有界面组件配置 */ + export function initConfigs(uicm: UIConfigMap) { + for (const key in uicm) { + configs[key] = uicm[key]; + } + } +} \ No newline at end of file diff --git a/assets/core/gui/Gui.ts.meta b/assets/core/gui/Gui.ts.meta new file mode 100644 index 0000000..0dd4546 --- /dev/null +++ b/assets/core/gui/Gui.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "51e09b11-d9ab-453b-b637-74d6aa615806", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/core/gui/layer/LayerEnum.ts b/assets/core/gui/layer/LayerEnum.ts index e656455..70d1ebb 100644 --- a/assets/core/gui/layer/LayerEnum.ts +++ b/assets/core/gui/layer/LayerEnum.ts @@ -51,4 +51,4 @@ export enum LayerTypeCls { Game = "Game", /** 自定义节点层 */ Node = "Node" -} +} \ No newline at end of file diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index 3d6e7a9..922df59 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -1,14 +1,15 @@ import { Camera, Layers, Node, ResolutionPolicy, SafeArea, Widget, screen, view, warn } from "cc"; import { resLoader } from "../../common/loader/ResLoader"; import { oops } from "../../Oops"; +import { gui } from "../Gui"; import { LayerDialog } from "./LayerDialog"; import { LayerCustomType, LayerTypeCls, UIConfigMap, Uiid } from "./LayerEnum"; +import { LayerGame } from "./LayerGame"; import { LayerNotify } from "./LayerNotify"; import { LayerPopUp } from "./LayerPopup"; import { LayerUI } from "./LayerUI"; import { LayerUIElement, UICallbacks } from "./LayerUIElement"; import { UIConfig } from "./UIConfig"; -import { LayerGame } from "./LayerGame"; /** 界面层级管理器 */ export class LayerManager { @@ -31,7 +32,7 @@ export class LayerManager { /** 消息提示控制器,请使用show方法来显示 */ private notify!: LayerNotify; /** UI配置 */ - private configs: UIConfigMap = {}; + // private configs: UIConfigMap = {}; /** 界面层集合 - 无自定义类型 */ private uiLayers: Map = new Map(); /** 界面层组件集合 */ @@ -135,9 +136,11 @@ export class LayerManager { /** * 初始化所有UI的配置对象 * @param configs 配置对象 + * @deprecated 后续将界面配置通过界面视图组件注册,使用gui.register注册每一个界面 */ init(configs: UIConfigMap): void { - this.configs = configs; + // this.configs = configs; + gui.initConfigs(configs); } /** @@ -179,15 +182,18 @@ export class LayerManager { if (typeof uiid === 'object') { if (uiid.bundle == null) uiid.bundle = resLoader.defaultBundleName; key = uiid.bundle + "_" + uiid.prefab; - config = this.configs[key]; + // config = this.configs[key]; + config = gui.getConfig(key); if (config == null) { config = uiid; - this.configs[key] = uiid; + // this.configs[key] = uiid; + gui.setConfig(key, uiid); } } else { key = uiid.toString(); - config = this.configs[uiid]; + // config = this.configs[uiid]; + config = gui.getConfig(key); if (config == null) { console.error(`打开编号为【${uiid}】的界面失败,配置信息不存在`); } @@ -274,7 +280,8 @@ export class LayerManager { if (comp && comp.params) { // 释放显示的界面 if (node.parent) { - let uiid = this.configs[comp.params.uiid]; + // let uiid = this.configs[comp.params.uiid]; + let uiid = gui.getConfig(comp.params.uiid); this.remove(uiid, isDestroy); } // 释放缓存中的界面 diff --git a/assets/core/gui/layer/LayerUIElement.ts b/assets/core/gui/layer/LayerUIElement.ts index 6c9c8c9..95fa612 100644 --- a/assets/core/gui/layer/LayerUIElement.ts +++ b/assets/core/gui/layer/LayerUIElement.ts @@ -91,7 +91,7 @@ export class LayerUIElement extends Component { // 释放界面相关资源 oops.res.release(uip.config.prefab, uip.config.bundle); - oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`); + // oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`); } else { this.node.removeFromParent(); @@ -134,6 +134,14 @@ export class UIParams { node: Node = null!; } +/** 界面关闭参数 */ +export interface UIRemove { + /** 关闭是否释放资源内存 */ + isDestroy?: boolean; + /** 界面动画播放完关闭事件 */ + onRemoved?: Function; +} + /*** 界面回调参数对象定义 */ export interface UICallbacks { /** diff --git a/assets/libs/ecs/ECS.ts b/assets/libs/ecs/ECS.ts index 19b120d..65dacff 100644 --- a/assets/libs/ecs/ECS.ts +++ b/assets/libs/ecs/ECS.ts @@ -42,6 +42,7 @@ export namespace ecs { export interface IComp { canRecycle: boolean; ent: Entity; + tid: number; reset(): void; } @@ -145,13 +146,10 @@ export namespace ecs { if (ctor.tid === -1) { ctor.tid = ECSModel.compTid++; ctor.compName = name; + ECSModel.compCtors.push(ctor); // 注册不同类型的组件 if (canNew) { - ECSModel.compCtors.push(ctor); // 注册不同类型的组件 ECSModel.compPools.set(ctor.tid, []); } - else { - ECSModel.compCtors.push(null!); - } ECSModel.compAddOrRemove.set(ctor.tid, []); } else { diff --git a/assets/libs/ecs/ECSComp.ts b/assets/libs/ecs/ECSComp.ts index ad0f9f8..41ead31 100644 --- a/assets/libs/ecs/ECSComp.ts +++ b/assets/libs/ecs/ECSComp.ts @@ -14,18 +14,18 @@ import { ECSEntity } from "./ECSEntity"; export abstract class ECSComp implements ecs.IComp { /** 组件的类型编号,-1表示未给该组件分配编号 */ static tid: number = -1; - /** 组件名 */ static compName: string; - /** 拥有该组件的实体 */ - ent!: ECSEntity; - /** * 是否可回收组件对象,默认情况下都是可回收的 * 注:如果该组件对象是由ecs系统外部创建的,则不可回收,需要用户自己手动进行回收 */ canRecycle: boolean = true; + /** 拥有该组件的实体 */ + ent!: ECSEntity; + /** 组件的类型编号 */ + tid: number = -1; /** * 组件被回收时会调用这个接口。可以在这里重置数据,或者解除引用 diff --git a/assets/libs/ecs/ECSEntity.ts b/assets/libs/ecs/ECSEntity.ts index a790a90..09511c9 100644 --- a/assets/libs/ecs/ECSEntity.ts +++ b/assets/libs/ecs/ECSEntity.ts @@ -154,6 +154,7 @@ export class ECSEntity { // @ts-ignore this[ctor.compName] = comp; this.compTid2Ctor.set(compTid, ctor); + comp.tid = compTid; comp.ent = this; // 广播实体添加组件的消息 broadcastCompAddOrRemove(this, compTid); @@ -173,9 +174,11 @@ export class ECSEntity { this[tmpCtor.compName] = ctor; this.compTid2Ctor.set(compTid, tmpCtor); //@ts-ignore - ctor.ent = this; + ctor.tid = compTid; //@ts-ignore ctor.canRecycle = false; + //@ts-ignore + ctor.ent = this; broadcastCompAddOrRemove(this, compTid); return this; diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index 814d300..784c5c4 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -5,11 +5,11 @@ * @LastEditTime: 2022-09-06 17:20:51 */ -import { _decorator } from 'cc'; -import { GameComponent } from './GameComponent'; +import { UIRemove } from '../../core/gui/layer/LayerUIElement'; import { ecs } from '../../libs/ecs/ECS'; - -const { ccclass, property } = _decorator; +import { ECSModel } from '../../libs/ecs/ECSModel'; +import { GameComponent } from './GameComponent'; +import { ModuleUtil } from './ModuleUtil'; /** * 游戏显示对象组件 @@ -34,13 +34,19 @@ export class RoleViewComp extends CCComp { } } */ -@ccclass('CCComp') export abstract class CCComp extends GameComponent implements ecs.IComp { static tid: number = -1; static compName: string; canRecycle!: boolean; ent!: ecs.Entity; + tid: number = -1; + + /** 从父节点移除自己 */ + remove(params?: UIRemove) { + const cct = ECSModel.compCtors[this.tid]; + ModuleUtil.remove(this.ent, cct, params); + } abstract reset(): void; } \ No newline at end of file diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index 55b7046..d87514e 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -5,11 +5,11 @@ * @LastEditTime: 2022-09-06 17:22:05 */ -import { _decorator } from 'cc'; +import { UIRemove } from '../../core/gui/layer/LayerUIElement'; import { ecs } from '../../libs/ecs/ECS'; +import { ECSModel } from '../../libs/ecs/ECSModel'; import VMParent from '../../libs/model-view/VMParent'; - -const { ccclass, property } = _decorator; +import { ModuleUtil } from './ModuleUtil'; /** * 支持 MVVM 功能的游戏显示对象组件 @@ -46,13 +46,19 @@ export class LoadingViewComp extends CCVMParentComp { } } */ -@ccclass('CCVMParentComp') export abstract class CCVMParentComp extends VMParent implements ecs.IComp { static tid: number = -1; static compName: string; canRecycle!: boolean; ent!: ecs.Entity; + tid: number = -1; + + /** 从父节点移除自己 */ + remove(params?: UIRemove) { + const cct = ECSModel.compCtors[this.tid]; + ModuleUtil.remove(this.ent, cct, params); + } abstract reset(): void; } \ No newline at end of file diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index bc29552..0b1a041 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -11,6 +11,7 @@ import { IAudioParams } from "../../core/common/audio/IAudio"; import { EventDispatcher } from "../../core/common/event/EventDispatcher"; import { EventMessage, ListenerFunc } from "../../core/common/event/EventMessage"; import { AssetType, CompleteCallback, Paths, ProgressCallback, resLoader } from "../../core/common/loader/ResLoader"; +import { LayerUIElement, UIRemove } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; const { ccclass } = _decorator; @@ -480,6 +481,23 @@ export class GameComponent extends Component { /** 游戏旋转屏幕事件回调 */ protected onGameOrientation(): void { } //#endregion + + /** 移除自己 */ + remove(params?: UIRemove) { + if (params == null) { + params = { isDestroy: true }; + } + else { + if (params.isDestroy == null) params.isDestroy = true; + } + + const comp = this.node.getComponent(LayerUIElement); + if (comp) { + if (params.onRemoved) comp.onCloseWindowBefore = params.onRemoved; + oops.gui.removeByNode(this.node, params.isDestroy); + } + } + protected onDestroy() { // 释放消息对象 if (this._event) { diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/ModuleUtil.ts index 7814aa1..826fe05 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/ModuleUtil.ts @@ -2,7 +2,7 @@ import { Node, __private } from "cc"; import { oops } from "../../core/Oops"; import { resLoader } from "../../core/common/loader/ResLoader"; import { Uiid } from "../../core/gui/layer/LayerEnum"; -import { LayerUIElement, UICallbacks } from "../../core/gui/layer/LayerUIElement"; +import { LayerUIElement, UICallbacks, UIRemove } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; import { ecs } from "../../libs/ecs/ECS"; import { CompType } from "../../libs/ecs/ECSModel"; @@ -12,12 +12,98 @@ import { CCVMParentComp } from "./CCVMParentComp"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; export class ModuleUtil { + /** + * 异步添加视图层组件 + * @param ent 模块实体 + * @param ctor 界面逻辑组件 + * @param uiArgs 界面参数 + * @returns 界面节点 + */ + static add(ent: ecs.Entity, ctor: ECSCtor, uiArgs: any = null): Promise { + return new Promise((resolve, reject) => { + const uic: UICallbacks = { + onAdded: (node: Node, params: any) => { + const comp = node.getComponent(ctor) as ecs.Comp; + ent.add(comp); + resolve(node); + }, + onLoadFailure: () => { + resolve(null); + } + }; + + //@ts-ignore + const key = ctor.oopsGuiKey; + if (key) { + oops.gui.open(key, uiArgs, uic); + } + else { + console.error(`${key} 界面组件未使用 gui.register 注册`); + } + }); + } + + /** + * 业务实体上移除界面组件 + * @param ent 模块实体 + * @param ctor 界面逻辑组件 + * @param isDestroy 是否释放界面缓存(默认为释放界面缓存) + * @param onRemoved 窗口关闭完成事件 + */ + static remove(ent: ecs.Entity, ctor: CompType, params?: UIRemove) { + if (params == null) { + params = { isDestroy: true }; + } + else { + if (params.isDestroy == null) params.isDestroy = true; + } + + //@ts-ignore + const key = ctor.oopsGuiKey; + if (key) { + const node = oops.gui.get(key); + if (node == null) { + console.error(`${key} 界面重复关闭`); + return; + } + + const comp = node.getComponent(LayerUIElement); + if (comp) { + comp.onCloseWindowBefore = () => { + if (params.isDestroy) ent.remove(ctor); + if (params.onRemoved) params.onRemoved(); + }; + oops.gui.remove(key, params.isDestroy); + } + } + else { + if (params.isDestroy) ent.remove(ctor); + if (params.onRemoved) params.onRemoved(); + } + } + + /** + * 通过资源内存中获取预制上的组件添加到ECS实体中 + * @param ent 模块实体 + * @param ctor 界面逻辑组件 + * @param parent 显示对象父级 + * @param path 显示资源地址 + * @param bundleName 资源包名称 + */ + static addView(ent: ecs.Entity, ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { + const node = ViewUtil.createPrefabNode(path, bundleName); + const comp = node.getComponent(ctor)!; + ent.add(comp); + node.parent = parent; + } + /** * 添加界面组件 * @param ent 模块实体 * @param ctor 界面逻辑组件 * @param uiId 界面资源编号 * @param uiArgs 界面参数 + * @deprecated 使用gui.register注册的界面组件,可使用add方法打开 */ static addViewUi(ent: ecs.Entity, ctor: ECSCtor, uiId: Uiid, uiArgs: any = null) { const uic: UICallbacks = { @@ -37,6 +123,7 @@ export class ModuleUtil { * @param uiId 界面资源编号 * @param uiArgs 界面参数 * @returns 界面节点 + * @deprecated 使用gui.register注册的界面组件,可使用add方法打开 */ static addViewUiAsync(ent: ecs.Entity, ctor: ECSCtor, uiId: Uiid, uiArgs: any = null): Promise { return new Promise((resolve, reject) => { @@ -54,21 +141,6 @@ export class ModuleUtil { }); } - /** - * 通过资源内存中获取预制上的组件添加到ECS实体中 - * @param ent 模块实体 - * @param ctor 界面逻辑组件 - * @param parent 显示对象父级 - * @param url 显示资源地址 - * @param bundleName 资源包名称 - */ - static addView(ent: ecs.Entity, ctor: ECSCtor, parent: Node, url: string, bundleName: string = resLoader.defaultBundleName) { - const node = ViewUtil.createPrefabNode(url, bundleName); - const comp = node.getComponent(ctor)!; - ent.add(comp); - node.parent = parent; - } - /** * 业务实体上移除界面组件 * @param ent 模块实体 @@ -76,6 +148,7 @@ export class ModuleUtil { * @param uiId 界面资源编号 * @param isDestroy 是否释放界面缓存(默认为释放界面缓存) * @param onRemoved 窗口关闭完成事件 + * @deprecated 使用gui.register注册的界面组件,可使用remove方法移除 */ static removeViewUi(ent: ecs.Entity, ctor: CompType, uiId: Uiid, isDestroy: boolean = true, onRemoved?: Function) { const node = oops.gui.get(uiId); diff --git a/assets/module/config/GameConfig.ts b/assets/module/config/GameConfig.ts index 2c0cf59..06e7eca 100644 --- a/assets/module/config/GameConfig.ts +++ b/assets/module/config/GameConfig.ts @@ -6,6 +6,7 @@ */ import { oops } from "../../core/Oops"; +/** 游戏自定义参数分组类型 */ export enum GameConfigCustomType { /** 开发环境 */ Dev = "dev",