From 4f3e965b08765435b15d7c5b94d6659360b90041 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 5 Sep 2025 11:47:42 +0800 Subject: [PATCH 01/37] =?UTF-8?q?=E4=BC=98=E5=8C=96LayerDialog=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerDialog.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/assets/core/gui/layer/LayerDialog.ts b/assets/core/gui/layer/LayerDialog.ts index 7f9a150..60d0ee4 100644 --- a/assets/core/gui/layer/LayerDialog.ts +++ b/assets/core/gui/layer/LayerDialog.ts @@ -67,9 +67,7 @@ export class LayerDialog extends LayerPopUp { protected closeUI() { if (this.params.length == 0) { - this.black.enabled = false; - this.closeVacancyRemove(); - this.closeMask() + super.closeUI(); } } -- Gitee From dfe27e7442c61fb5e9c50fe970c8ae9ece194611 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 8 Sep 2025 16:17:31 +0800 Subject: [PATCH 02/37] =?UTF-8?q?GameConfig=E5=AF=B9=E8=B1=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E5=85=A8=E5=B1=80=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=88=86=E7=BB=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/game/GameManager.ts | 6 ++-- assets/module/config/GameConfig.ts | 45 +++++++++++++++++------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/assets/core/game/GameManager.ts b/assets/core/game/GameManager.ts index 2f5d64c..678ad23 100644 --- a/assets/core/game/GameManager.ts +++ b/assets/core/game/GameManager.ts @@ -54,7 +54,9 @@ export class GameManager { } // 自定义节点排序索引 - if (params && params.siblingIndex) node.setSiblingIndex(params.siblingIndex); + if (params) { + if (params.siblingIndex) node.setSiblingIndex(params.siblingIndex); + } resolve(node); }); @@ -70,4 +72,4 @@ export class GameManager { //@ts-ignore return director.globalGameTimeScale; } -} +} \ No newline at end of file diff --git a/assets/module/config/GameConfig.ts b/assets/module/config/GameConfig.ts index af0a99c..2c0cf59 100644 --- a/assets/module/config/GameConfig.ts +++ b/assets/module/config/GameConfig.ts @@ -4,18 +4,22 @@ * @LastEditors: dgflash * @LastEditTime: 2023-02-14 14:27:22 */ - import { oops } from "../../core/Oops"; +export enum GameConfigCustomType { + /** 开发环境 */ + Dev = "dev", + /** 测试环境 */ + Test = "test", + /** 生产环境 */ + Prod = "prod", +} + /* 游戏配置解析,对应 resources/config/config.json 配置 */ export class GameConfig { /** 客户端版本号配置 */ get version(): string { - return this._data["config"]["version"]; - } - /** 包名 */ - get package(): string { - return this._data["config"]["package"]; + return this._data.config.version; } /** 游戏每秒传输帧数 */ get frameRate(): number { @@ -55,22 +59,10 @@ export class GameConfig { return this._data.language.default || "zh"; } - /** 是否启用远程资源 */ - get bundleEnable(): string { - return this._data.bundle.enable; - } - /** 远程资源服务器地址 */ - get bundleServer(): string { - return this._data.bundle.server; - } /** 远程资源名 */ get bundleDefault(): string { return this._data.bundle.default; } - /** 远程所有资源包配置 */ - get bundlePackages(): string { - return this._data.bundle.packages; - } /** 加载界面资源超时提示 */ get loadingTimeoutGui(): number { @@ -82,7 +74,7 @@ export class GameConfig { return this._data.config.mobileSafeArea || false; } - private readonly _data: any = null; + private _data: any = null; /** 游戏配置数据 */ get data(): any { return this._data; @@ -93,4 +85,19 @@ export class GameConfig { oops.log.logConfig(this._data, "游戏配置"); } + + private _customType: GameConfigCustomType = GameConfigCustomType.Dev; + + /** + * 设置自定义游戏参数配置类型 + * @param type + */ + setCustomType(type: GameConfigCustomType) { + this._customType = type; + } + + /** 获取游戏自定义配置 */ + get custom(): any { + return this.data.custom[this._customType]; + } } \ No newline at end of file -- Gitee From b4ea586d1a21c8093f09b2801465214c02ed190a Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 17:19:57 +0800 Subject: [PATCH 03/37] =?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", -- Gitee From f592ebb68486dbcaa76edd562444072fa860c196 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 17:28:37 +0800 Subject: [PATCH 04/37] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/Gui.ts | 2 +- assets/core/gui/layer/LayerManager.ts | 16 +++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/assets/core/gui/Gui.ts b/assets/core/gui/Gui.ts index 5ffdece..4ddc09d 100644 --- a/assets/core/gui/Gui.ts +++ b/assets/core/gui/Gui.ts @@ -22,7 +22,7 @@ export namespace gui { configs[key] = config; } - /** 获取所有界面组件配置 */ + /** 初始化界面组件配置 */ export function initConfigs(uicm: UIConfigMap) { for (const key in uicm) { configs[key] = uicm[key]; diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index 922df59..a4e5184 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -1,10 +1,11 @@ -import { Camera, Layers, Node, ResolutionPolicy, SafeArea, Widget, screen, view, warn } from "cc"; +import { Camera, Node, ResolutionPolicy, SafeArea, 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 { LayerHelper } from "./LayerHelper"; import { LayerNotify } from "./LayerNotify"; import { LayerPopUp } from "./LayerPopup"; import { LayerUI } from "./LayerUI"; @@ -31,8 +32,6 @@ export class LayerManager { /** 消息提示控制器,请使用show方法来显示 */ private notify!: LayerNotify; - /** UI配置 */ - // private configs: UIConfigMap = {}; /** 界面层集合 - 无自定义类型 */ private uiLayers: Map = new Map(); /** 界面层组件集合 */ @@ -182,17 +181,14 @@ 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 = gui.getConfig(key); if (config == null) { config = uiid; - // this.configs[key] = uiid; gui.setConfig(key, uiid); } } else { key = uiid.toString(); - // config = this.configs[uiid]; config = gui.getConfig(key); if (config == null) { console.error(`打开编号为【${uiid}】的界面失败,配置信息不存在`); @@ -280,7 +276,6 @@ export class LayerManager { if (comp && comp.params) { // 释放显示的界面 if (node.parent) { - // let uiid = this.configs[comp.params.uiid]; let uiid = gui.getConfig(comp.params.uiid); this.remove(uiid, isDestroy); } @@ -387,12 +382,7 @@ export class LayerManager { private create_node(name: string) { const node = new Node(name); - node.layer = Layers.Enum.UI_2D; - const w: Widget = node.addComponent(Widget); - w.isAlignLeft = w.isAlignRight = w.isAlignTop = w.isAlignBottom = true; - w.left = w.right = w.top = w.bottom = 0; - w.alignMode = 2; - w.enabled = true; + LayerHelper.setFullScreen(node); return node; } } \ No newline at end of file -- Gitee From 819ab99bbddac20f4a0daaf3fea0adffacb1969a Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 18:29:43 +0800 Subject: [PATCH 05/37] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Gui=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/Gui.ts | 40 +++++++++++++++++--------- assets/core/gui/layer/LayerEnum.ts | 2 +- assets/core/gui/layer/LayerManager.ts | 21 ++++++++------ assets/libs/ecs/ECS.ts | 2 +- assets/module/common/CCComp.ts | 7 ++++- assets/module/common/CCVMParentComp.ts | 7 ++++- assets/module/common/ModuleUtil.ts | 5 ++-- 7 files changed, 56 insertions(+), 28 deletions(-) diff --git a/assets/core/gui/Gui.ts b/assets/core/gui/Gui.ts index 4ddc09d..96f64cc 100644 --- a/assets/core/gui/Gui.ts +++ b/assets/core/gui/Gui.ts @@ -7,25 +7,37 @@ export namespace gui { /** 注册界面组件 */ export function register(key: string, config: UIConfig) { return function (ctor: any) { - ctor.oopsGuiKey = key; - setConfig(key, config); + //@ts-ignore + ctor[gui.internal.GUI_KEY] = key; + internal.setConfig(key, config); }; } - /** 获取界面组件配置 */ - export function getConfig(key: string) { - return configs[key]; - } + /** 框架内部使用方法 */ + export namespace internal { + /** 界面唯一标记变量名 */ + export const GUI_KEY = "OOPS_GUI_KEY"; + /** 获取界面组件配置 */ + export function getConfig(key: string) { + return configs[key]; + } - /** 获取界面组件配置 */ - export function setConfig(key: string, config: UIConfig) { - configs[key] = config; - } + /** 获取界面组件配置 */ + export function setConfig(key: string, config: UIConfig) { + let c = getConfig(key); + if (c == null) { + configs[key] = config; + } + else { + console.error(`界面${key}重复注册`); + } + } - /** 初始化界面组件配置 */ - export function initConfigs(uicm: UIConfigMap) { - for (const key in uicm) { - configs[key] = uicm[key]; + /** 初始化界面组件配置 */ + 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/layer/LayerEnum.ts b/assets/core/gui/layer/LayerEnum.ts index 70d1ebb..9879f98 100644 --- a/assets/core/gui/layer/LayerEnum.ts +++ b/assets/core/gui/layer/LayerEnum.ts @@ -1,7 +1,7 @@ import { UIConfig } from "./UIConfig"; /** 界面编号 */ -export type Uiid = number | string | UIConfig; +export type Uiid = number | string | UIConfig | Function; /** 界面配置集合 */ export type UIConfigMap = { [key: string]: UIConfig } diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index a4e5184..aa4ea04 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -135,11 +135,9 @@ export class LayerManager { /** * 初始化所有UI的配置对象 * @param configs 配置对象 - * @deprecated 后续将界面配置通过界面视图组件注册,使用gui.register注册每一个界面 */ init(configs: UIConfigMap): void { - // this.configs = configs; - gui.initConfigs(configs); + gui.internal.initConfigs(configs); } /** @@ -177,19 +175,26 @@ export class LayerManager { let key = ""; let config: UIConfig = null!; - // 确定 key 和 config + // 界面配置 if (typeof uiid === 'object') { if (uiid.bundle == null) uiid.bundle = resLoader.defaultBundleName; key = uiid.bundle + "_" + uiid.prefab; - config = gui.getConfig(key); + config = gui.internal.getConfig(key); if (config == null) { config = uiid; - gui.setConfig(key, uiid); + gui.internal.setConfig(key, uiid); } } + // 界面对象 - 配合gui.register使用 + else if (uiid instanceof Function) { + //@ts-ignore + key = uiid[gui.internal.GUI_KEY]; + config = gui.internal.getConfig(key); + } + // 界面唯一标记 else { key = uiid.toString(); - config = gui.getConfig(key); + config = gui.internal.getConfig(key); if (config == null) { console.error(`打开编号为【${uiid}】的界面失败,配置信息不存在`); } @@ -276,7 +281,7 @@ export class LayerManager { if (comp && comp.params) { // 释放显示的界面 if (node.parent) { - let uiid = gui.getConfig(comp.params.uiid); + let uiid = gui.internal.getConfig(comp.params.uiid); this.remove(uiid, isDestroy); } // 释放缓存中的界面 diff --git a/assets/libs/ecs/ECS.ts b/assets/libs/ecs/ECS.ts index 65dacff..fbc2431 100644 --- a/assets/libs/ecs/ECS.ts +++ b/assets/libs/ecs/ECS.ts @@ -153,7 +153,7 @@ export namespace ecs { ECSModel.compAddOrRemove.set(ctor.tid, []); } else { - throw new Error(`重复注册组件: ${name}.`); + throw new Error(`ECS 组件重复注册: ${name}.`); } } } diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index 784c5c4..639307f 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -45,7 +45,12 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { /** 从父节点移除自己 */ remove(params?: UIRemove) { const cct = ECSModel.compCtors[this.tid]; - ModuleUtil.remove(this.ent, cct, params); + if (this.ent) { + ModuleUtil.remove(this.ent, cct, params); + } + else { + console.error(`组件 ${this.name} 移除失败,实体不存在`); + } } abstract reset(): void; diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index d87514e..e9e6be4 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -57,7 +57,12 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { /** 从父节点移除自己 */ remove(params?: UIRemove) { const cct = ECSModel.compCtors[this.tid]; - ModuleUtil.remove(this.ent, cct, params); + if (this.ent) { + ModuleUtil.remove(this.ent, cct, params); + } + else { + console.error(`组件 ${this.name} 移除失败,实体不存在`); + } } abstract reset(): void; diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/ModuleUtil.ts index 826fe05..239b7a5 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/ModuleUtil.ts @@ -1,6 +1,7 @@ import { Node, __private } from "cc"; import { oops } from "../../core/Oops"; import { resLoader } from "../../core/common/loader/ResLoader"; +import { gui } from "../../core/gui/Gui"; import { Uiid } from "../../core/gui/layer/LayerEnum"; import { LayerUIElement, UICallbacks, UIRemove } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; @@ -33,7 +34,7 @@ export class ModuleUtil { }; //@ts-ignore - const key = ctor.oopsGuiKey; + const key = ctor[gui.internal.GUI_KEY]; if (key) { oops.gui.open(key, uiArgs, uic); } @@ -59,7 +60,7 @@ export class ModuleUtil { } //@ts-ignore - const key = ctor.oopsGuiKey; + const key = ctor[gui.internal.GUI_KEY]; if (key) { const node = oops.gui.get(key); if (node == null) { -- Gitee From 4ad205d309c15031e279c54acb06b2726022db7b Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 20:07:32 +0800 Subject: [PATCH 06/37] =?UTF-8?q?ModuleUtil.addGui=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E7=AA=97=E5=8F=A3=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerUIElement.ts | 2 +- assets/module/common/CCComp.ts | 2 +- assets/module/common/CCVMParentComp.ts | 2 +- assets/module/common/ModuleUtil.ts | 8 ++++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/assets/core/gui/layer/LayerUIElement.ts b/assets/core/gui/layer/LayerUIElement.ts index 95fa612..19e3131 100644 --- a/assets/core/gui/layer/LayerUIElement.ts +++ b/assets/core/gui/layer/LayerUIElement.ts @@ -24,7 +24,7 @@ export class LayerUIElement extends Component { /** 界面关闭回调 - 包括关闭动画播放完(辅助框架内存业务流程使用) */ private onCloseWindow: Function = null!; - /** 窗口添加 */ + /** 添加界面且界面设置到父节点之前 */ add(): Promise { return new Promise(async (resolve, reject) => { // 触发窗口组件上添加到父节点后的事件 diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index 639307f..e2738b5 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -46,7 +46,7 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { remove(params?: UIRemove) { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.remove(this.ent, cct, params); + ModuleUtil.removeGui(this.ent, cct, params); } else { console.error(`组件 ${this.name} 移除失败,实体不存在`); diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index e9e6be4..e5557a1 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -58,7 +58,7 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { remove(params?: UIRemove) { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.remove(this.ent, cct, params); + ModuleUtil.removeGui(this.ent, cct, params); } else { console.error(`组件 ${this.name} 移除失败,实体不存在`); diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/ModuleUtil.ts index 239b7a5..c84112d 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/ModuleUtil.ts @@ -20,15 +20,17 @@ export class ModuleUtil { * @param uiArgs 界面参数 * @returns 界面节点 */ - static add(ent: ecs.Entity, ctor: ECSCtor, uiArgs: any = null): Promise { + static addGui(ent: ecs.Entity, ctor: ECSCtor, uiArgs?: any, anim?: UICallbacks): 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); + if (anim && anim.onAdded) anim.onAdded(node, params); resolve(node); }, onLoadFailure: () => { + if (anim && anim.onLoadFailure) anim.onLoadFailure(); resolve(null); } }; @@ -51,7 +53,7 @@ export class ModuleUtil { * @param isDestroy 是否释放界面缓存(默认为释放界面缓存) * @param onRemoved 窗口关闭完成事件 */ - static remove(ent: ecs.Entity, ctor: CompType, params?: UIRemove) { + static removeGui(ent: ecs.Entity, ctor: CompType, params?: UIRemove) { if (params == null) { params = { isDestroy: true }; } @@ -98,6 +100,7 @@ export class ModuleUtil { node.parent = parent; } + //#region deprecated /** * 添加界面组件 * @param ent 模块实体 @@ -168,4 +171,5 @@ export class ModuleUtil { oops.gui.remove(uiId, isDestroy); } } + //#endregion } \ No newline at end of file -- Gitee From 22888a17ec95dc01f8002b1af96f44bab67dacd3 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 9 Sep 2025 20:15:16 +0800 Subject: [PATCH 07/37] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/ModuleUtil.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/ModuleUtil.ts index c84112d..187ed7c 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/ModuleUtil.ts @@ -18,6 +18,7 @@ export class ModuleUtil { * @param ent 模块实体 * @param ctor 界面逻辑组件 * @param uiArgs 界面参数 + * @param anim 界面打开与关闭动画 * @returns 界面节点 */ static addGui(ent: ecs.Entity, ctor: ECSCtor, uiArgs?: any, anim?: UICallbacks): Promise { @@ -50,8 +51,7 @@ export class ModuleUtil { * 业务实体上移除界面组件 * @param ent 模块实体 * @param ctor 界面逻辑组件 - * @param isDestroy 是否释放界面缓存(默认为释放界面缓存) - * @param onRemoved 窗口关闭完成事件 + * @param params 界面关闭参数 */ static removeGui(ent: ecs.Entity, ctor: CompType, params?: UIRemove) { if (params == null) { -- Gitee From 92e8ccbe9bfe21c54af0b9e067aab215da4ad0d9 Mon Sep 17 00:00:00 2001 From: dgflash Date: Wed, 10 Sep 2025 18:35:44 +0800 Subject: [PATCH 08/37] =?UTF-8?q?=E9=87=8D=E6=9E=84GUI=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=89=93=E5=BC=80=E7=95=8C=E9=9D=A2=E4=B8=8E=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E7=9A=84=E5=8F=82=E6=95=B0=EF=BC=8C=E6=96=B9?= =?UTF-8?q?=E4=BE=BF=E5=90=8E=E7=BB=AD=E6=89=A9=E5=B1=95=E6=96=B0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E8=80=8C=E4=BF=9D=E6=8C=81=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=B8=8D=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerDialog.ts | 73 ++++----- assets/core/gui/layer/LayerManager.ts | 101 ++++-------- assets/core/gui/layer/LayerPopup.ts | 20 +-- assets/core/gui/layer/LayerUI.ts | 209 +++++++++++++----------- assets/core/gui/layer/LayerUIElement.ts | 90 +++++----- assets/core/gui/layer/UIConfig.ts | 2 +- assets/module/common/CCComp.ts | 7 +- assets/module/common/CCVMParentComp.ts | 7 +- assets/module/common/GameComponent.ts | 14 +- assets/module/common/ModuleUtil.ts | 134 +++------------ 10 files changed, 267 insertions(+), 390 deletions(-) diff --git a/assets/core/gui/layer/LayerDialog.ts b/assets/core/gui/layer/LayerDialog.ts index 60d0ee4..bc80767 100644 --- a/assets/core/gui/layer/LayerDialog.ts +++ b/assets/core/gui/layer/LayerDialog.ts @@ -4,9 +4,9 @@ * @LastEditors: dgflash * @LastEditTime: 2023-07-24 17:14:57 */ - +import { Node } from "cc"; import { LayerPopUp } from "./LayerPopup"; -import { UICallbacks, UIParams } from "./LayerUIElement"; +import { UIParam, UIState } from "./LayerUIElement"; import { UIConfig } from "./UIConfig"; /** 模式弹窗数据 */ @@ -16,9 +16,7 @@ type DialogParam = { /** 窗口配置 */ config: UIConfig; /** 窗口附加参数 */ - params?: any; - /** 窗口回调 */ - callbacks?: UICallbacks; + params?: UIParam; } /* @@ -27,54 +25,55 @@ type DialogParam = { export class LayerDialog extends LayerPopUp { /** 窗口调用参数队列 */ private params: Array = []; + /** 当前打开的界面 */ + private current: Node = null!; - add(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) { - // 控制同一时间只能显示一个模式窗口 - if (this.ui_nodes.size > 0) { - this.params.push({ - uiid: uiid, - config: config, - params: params, - callbacks: callbacks, - }); - return; - } - - this.show(uiid, config, params, callbacks); + /** + * 添加模式窗口 + * 1. 同时添加多个模式窗口时,第一个之后的窗口会先队列起来,在第一个关闭后在加载与显示第二个;同时方法返回节点保持只返回当前显示的界面节点 + */ + add(uiid: string, config: UIConfig, params?: UIParam): Promise { + return new Promise(async (resolve, reject) => { + // 控制同一时间只能显示一个模式窗口 + if (this.ui_nodes.size > 0) { + this.params.push({ + uiid: uiid, + config: config, + params: params + }); + resolve(this.current); + } + else { + this.current = await this.showDialog(uiid, config, params); + resolve(this.current); + } + }); } /** 显示模式弹窗 */ - private show(uiid: string, config: UIConfig, params?: any, callbacks?: UICallbacks) { - let uip = this.ui_cache.get(config.prefab); - if (uip == null) { - uip = new UIParams(); - uip.uiid = uiid; - uip.valid = true; - uip.config = config; - } - - uip.params = params || {}; - uip.callbacks = callbacks ?? {}; - this.ui_nodes.set(uip.config.prefab, uip); - - this.load(uip, config.bundle); + private showDialog(uiid: string, config: UIConfig, param?: UIParam): Promise { + return new Promise(async (resolve, reject) => { + let state = this.initUIConfig(uiid, config, param); + let node = await this.load(state, config.bundle); + resolve(node); + }); } - protected onCloseWindow(uip: UIParams) { - super.onCloseWindow(uip); + protected uiClose(state: UIState) { + super.uiClose(state); setTimeout(this.next.bind(this), 0); } - protected closeUI() { + protected closeBlack() { if (this.params.length == 0) { - super.closeUI(); + super.closeBlack(); } } private next() { if (this.params.length > 0) { let param = this.params.shift()!; - this.show(param.uiid, param.config, param.params, param.callbacks); + this.showDialog(param.uiid, param.config, param.params); } } } \ No newline at end of file diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index aa4ea04..3be745e 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -9,7 +9,7 @@ import { LayerHelper } from "./LayerHelper"; import { LayerNotify } from "./LayerNotify"; import { LayerPopUp } from "./LayerPopup"; import { LayerUI } from "./LayerUI"; -import { LayerUIElement, UICallbacks } from "./LayerUIElement"; +import { LayerUIElement, UIParam } from "./LayerUIElement"; import { UIConfig } from "./UIConfig"; /** 界面层级管理器 */ @@ -171,13 +171,13 @@ export class LayerManager { this.notify.waitClose(); } + /** 获取界面信息 */ private getInfo(uiid: Uiid): { key: string; config: UIConfig } { let key = ""; let config: UIConfig = null!; // 界面配置 if (typeof uiid === 'object') { - if (uiid.bundle == null) uiid.bundle = resLoader.defaultBundleName; key = uiid.bundle + "_" + uiid.prefab; config = gui.internal.getConfig(key); if (config == null) { @@ -205,8 +205,7 @@ export class LayerManager { /** * 同步打开一个窗口 * @param uiid 窗口唯一编号 - * @param uiArgs 窗口参数 - * @param callbacks 回调对象 + * @param param 窗口参数 * @example var uic: UICallbacks = { onAdded: (node: Node, params: any) => { @@ -218,50 +217,43 @@ export class LayerManager { }; oops.gui.open(UIID.Loading, null, uic); */ - open(uiid: Uiid, uiArgs: any = null, callbacks?: UICallbacks): void { + open(uiid: Uiid, param?: UIParam): Promise { + return new Promise(async (resolve, reject) => { + let info = this.getInfo(uiid); + let layer = this.uiLayers.get(info.config.layer); + if (layer) { + let node = await layer.add(info.key, info.config, param); + resolve(node); + } + else { + console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`); + } + }); + } + + /** 显示指定界面 */ + show(uiid: Uiid) { let info = this.getInfo(uiid); let layer = this.uiLayers.get(info.config.layer); if (layer) { - layer.add(info.key, info.config, uiArgs, callbacks); + layer.show(info.config.prefab); } else { console.error(`打开编号为【${uiid}】的界面失败,界面层不存在`); } } - /** - * 异步打开一个窗口 - * @param uiid 窗口唯一编号 - * @param uiArgs 窗口参数 - * @example - * var node = await oops.gui.openAsync(UIID.Loading); - */ - async openAsync(uiid: Uiid, uiArgs: any = null): Promise { - return new Promise((resolve, reject) => { - const callbacks: UICallbacks = { - onAdded: (node: Node, params: any) => { - resolve(node); - }, - onLoadFailure: () => { - resolve(null); - } - }; - this.open(uiid, uiArgs, callbacks); - }); - } - /** * 移除指定标识的窗口 * @param uiid 窗口唯一标识 - * @param isDestroy 移除后是否释放(默认释放内存) * @example * oops.gui.remove(UIID.Loading); */ - remove(uiid: Uiid, isDestroy: boolean = true) { + remove(uiid: Uiid) { let info = this.getInfo(uiid); let layer = this.uiLayers.get(info.config.layer); if (layer) { - layer.remove(info.config.prefab, isDestroy); + layer.remove(info.config.prefab); } else { console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`); @@ -271,25 +263,24 @@ export class LayerManager { /** * 通过界面节点移除 * @param node 窗口节点 - * @param isDestroy 移除后是否释放资源(默认释放内存) * @example * oops.gui.removeByNode(cc.Node); */ - removeByNode(node: Node, isDestroy: boolean = true) { + removeByNode(node: Node) { if (node instanceof Node) { let comp = node.getComponent(LayerUIElement); - if (comp && comp.params) { + if (comp && comp.state) { // 释放显示的界面 if (node.parent) { - let uiid = gui.internal.getConfig(comp.params.uiid); - this.remove(uiid, isDestroy); + let uiid = gui.internal.getConfig(comp.state.uiid); + this.remove(uiid); } // 释放缓存中的界面 - else if (isDestroy) { - let layer = this.uiLayers.get(comp.params.config.layer); + else { + let layer = this.uiLayers.get(comp.state.config.layer); if (layer) { // @ts-ignore 注:不对外使用 - layer.removeCache(comp.params.config.prefab); + layer.removeCache(comp.state.config.prefab); } } } @@ -303,34 +294,14 @@ export class LayerManager { /** * 场景替换 * @param removeUiId 移除场景编号 - * @param openUiId 新打开场景编号 - * @param uiArgs 新打开场景参数 + * @param openUiid 新打开场景编号 + * @param param 新打开场景参数 */ - replace(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null) { - const callbacks: UICallbacks = { - onAdded: (node: Node, params: any) => { - this.remove(removeUiId); - } - }; - this.open(openUiId, uiArgs, callbacks); - } - - /** - * 异步场景替换 - * @param removeUiId 移除场景编号 - * @param openUiId 新打开场景编号 - * @param uiArgs 新打开场景参数 - */ - replaceAsync(removeUiId: Uiid, openUiId: Uiid, uiArgs: any = null): Promise { - return new Promise(async (resolve, reject) => { - const node = await this.openAsync(openUiId, uiArgs); - if (node) { - this.remove(removeUiId); - resolve(node); - } - else { - resolve(null); - } + replace(removeUiId: Uiid, openUiid: Uiid, param?: UIParam): Promise { + return new Promise(async (resolve, reject) => { + let node = await this.open(openUiid, param); + this.remove(removeUiId); + resolve(node); }); } diff --git a/assets/core/gui/layer/LayerPopup.ts b/assets/core/gui/layer/LayerPopup.ts index 95d4d63..70c3479 100644 --- a/assets/core/gui/layer/LayerPopup.ts +++ b/assets/core/gui/layer/LayerPopup.ts @@ -7,7 +7,7 @@ import { BlockInputEvents, EventTouch, Node } from "cc"; import { ViewUtil } from "../../utils/ViewUtil"; import { PromptResType } from "../GuiEnum"; import { LayerUI } from "./LayerUI"; -import { UIParams } from "./LayerUIElement"; +import { UIState } from "./LayerUIElement"; import { UIConfig } from "./UIConfig"; /* 弹窗层,允许同时弹出多个窗口 */ @@ -32,12 +32,12 @@ export class LayerPopUp extends LayerUI { if (this.mask) this.mask.setSiblingIndex(this.children.length - 2); } - protected showUi(uip: UIParams): Promise { + protected uiInit(state: UIState): Promise { return new Promise(async (resolve) => { - const r = await super.showUi(uip); + const r = await super.uiInit(state); if (r) { // 界面加载完成显示时,启动触摸非窗口区域关闭 - this.openVacancyRemove(uip.config); + this.openVacancyRemove(state.config); // 界面加载完成显示时,层级事件阻挡 this.black.enabled = true; @@ -46,15 +46,15 @@ export class LayerPopUp extends LayerUI { }); } - protected onCloseWindow(uip: UIParams) { - super.onCloseWindow(uip); + protected uiClose(state: UIState) { + super.uiClose(state); // 界面关闭后,关闭触摸事件阻挡、关闭触摸非窗口区域关闭、关闭遮罩 - this.closeUI(); + this.closeBlack(); } /** 设置触摸事件阻挡 */ - protected closeUI() { + protected closeBlack() { // 所有弹窗关闭后,关闭事件阻挡功能 if (this.ui_nodes.size == 0) { if (this.black) this.black.enabled = false; @@ -120,13 +120,13 @@ export class LayerPopUp extends LayerUI { if (this.ui_nodes.size > 0) { let vp = this.ui_nodes.array[this.ui_nodes.size - 1]; if (vp.valid && vp.config.vacancy) { - this.remove(vp.config.prefab, vp.config.destroy); + this.remove(vp.config.prefab); } } } clear(isDestroy: boolean) { super.clear(isDestroy) - this.closeUI(); + this.closeBlack(); } } \ No newline at end of file diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index ebf9446..bb93ccb 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -1,19 +1,20 @@ import { instantiate, Node, Prefab, SafeArea } from "cc"; import { Collection } from "db://oops-framework/libs/collection/Collection"; +import { resLoader } from "../../common/loader/ResLoader"; import { oops } from "../../Oops"; import { Uiid } from "./LayerEnum"; import { LayerHelper } from "./LayerHelper"; -import { LayerUIElement, UICallbacks, UIParams } from "./LayerUIElement"; +import { LayerUIElement, UIParam, UIState } from "./LayerUIElement"; import { UIConfig } from "./UIConfig"; /** 界面层对象 */ export class LayerUI extends Node { - /** 全局窗口打开失败 */ + /** 全局窗口打开失败事件 */ onOpenFailure: Function = null!; /** 显示界面节点集合 */ - protected ui_nodes = new Collection(); + protected ui_nodes = new Collection(); /** 被移除的界面缓存数据 */ - protected ui_cache = new Map(); + protected ui_cache = new Map(); /** * UI基础层,允许添加多个预制件节点 @@ -28,71 +29,101 @@ export class LayerUI extends Node { * 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点 * @param config 界面配置数据 * @param params 自定义参数 - * @param callbacks 回调函数对象,可选 * @returns ture为成功,false为失败 */ - add(uiid: Uiid, config: UIConfig, params?: any, callbacks?: UICallbacks) { - if (this.ui_nodes.has(config.prefab)) { - console.warn(`路径为【${config.prefab}】的预制重复加载`); - return; - } - - // 检查缓存中是否存界面 - let uip = this.ui_cache.get(config.prefab); - if (uip == null) { - uip = new UIParams(); - uip.uiid = uiid.toString(); - uip.config = config; - } - this.ui_nodes.set(config.prefab, uip); + add(uiid: Uiid, config: UIConfig, params?: UIParam): Promise { + return new Promise(async (resolve, reject) => { + if (this.ui_nodes.has(config.prefab)) { + console.warn(`路径为【${config.prefab}】的预制重复加载`); + return; + } - uip.params = params ?? {}; - uip.callbacks = callbacks ?? {}; - uip.valid = true; + // 检查缓存中是否存界面 + let state = this.initUIConfig(uiid, config, params); + await this.load(state, config.bundle); + resolve(state.node); + }); + } - this.load(uip, config.bundle) + /** 初始化界面配置初始值 */ + protected initUIConfig(uiid: Uiid, config: UIConfig, params?: UIParam) { + let state = this.ui_cache.get(config.prefab); + if (state == null) { + if (config.bundle == null) config.bundle = resLoader.defaultBundleName; + if (config.destroy == null) config.destroy = true; + if (config.vacancy == null) config.vacancy = false; + if (config.mask == null) config.mask = false; + if (config.safeArea == null) config.safeArea = false; + + state = new UIState(); + state.uiid = uiid.toString(); + state.config = config; + } + state.params = params ?? {}; + state.valid = true; + this.ui_nodes.set(config.prefab, state); + return state; } /** * 加载界面资源 - * @param uip 显示参数 + * @param state 显示参数 * @param bundle 远程资源包名,如果为空就是默认本地资源包 */ - protected async load(uip: UIParams, bundle?: string) { - // 加载界面资源超时提示 - const timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); + protected async load(state: UIState, bundle: string = resLoader.defaultBundleName): Promise { + return new Promise(async (resolve, reject) => { + // 加载界面资源超时提示 + let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); + if (state.node == null) { + // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 + const res = await resLoader.loadAsync(bundle, state.config.prefab, Prefab); + if (res) { + state.node = instantiate(res); + + // 是否启动真机安全区域显示 + if (state.config.safeArea) state.node.addComponent(SafeArea); + + // 窗口事件委托 + const comp = state.node.addComponent(LayerUIElement); + comp.state = state; + } + else { + console.warn(`路径为【${state.config.prefab}】的预制加载失败`); + this.failure(state); + } + } - if (uip && uip.node) { - await this.showUi(uip); - } - else { - // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 - bundle = bundle || oops.res.defaultBundleName; - const res = await oops.res.loadAsync(bundle, uip.config.prefab, Prefab); - if (res) { - uip.node = instantiate(res); - - // 是否启动真机安全区域显示 - if (uip.config.safeArea) uip.node.addComponent(SafeArea); - - // 窗口事件委托 - const dc = uip.node.addComponent(LayerUIElement); - dc.params = uip; - //@ts-ignore - dc.onCloseWindow = this.onCloseWindow.bind(this); - - // 显示界面 - await this.showUi(uip); + // 关闭界面资源超时提示 + oops.gui.waitClose(); + clearTimeout(timerId); + + await this.uiInit(state); + + resolve(state.node); + }); + } + + /** + * 创建界面节点 + * @param state 视图参数 + */ + protected uiInit(state: UIState): Promise { + return new Promise(async (resolve, reject) => { + const comp = state.node.getComponent(LayerUIElement)!; + const r: boolean = await comp.add(); + if (r) { + state.valid = true; // 标记界面为使用状态 + if (!state.params.preload) { + state.params.preload = false; + state.node.parent = this; + } } else { - console.warn(`路径为【${uip.config.prefab}】的预制加载失败`); - this.failure(uip); + console.warn(`路径为【${state.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`); + this.failure(state); } - } - - // 关闭界面资源超时提示 - oops.gui.waitClose(); - clearTimeout(timerId); + resolve(r); + }); } /** 加载超时事件*/ @@ -101,74 +132,52 @@ export class LayerUI extends Node { } /** 窗口关闭事件 */ - protected onCloseWindow(vp: UIParams) { - this.ui_nodes.delete(vp.config.prefab); - } - - /** - * 创建界面节点 - * @param uip 视图参数 - */ - protected async showUi(uip: UIParams): Promise { - // 触发窗口添加事件 - const comp = uip.node.getComponent(LayerUIElement)!; - const r: boolean = await comp.add(); - if (r) { - uip.node.parent = this; - - // 标记界面为使用状态 - uip.valid = true; - } - else { - console.warn(`路径为【${uip.config.prefab}】的自定义预处理逻辑异常.检查预制上绑定的组件中 onAdded 方法,返回true才能正确完成窗口显示流程`); - this.failure(uip); - } - return r; + protected uiClose(state: UIState) { + this.ui_nodes.delete(state.config.prefab); } /** 打开窗口失败逻辑 */ - protected failure(uip: UIParams) { - this.onCloseWindow(uip); - uip.callbacks && uip.callbacks.onLoadFailure && uip.callbacks.onLoadFailure(); + protected failure(state: UIState) { + this.uiClose(state); this.onOpenFailure && this.onOpenFailure(); } /** * 根据预制件路径删除,预制件如在队列中也会被删除,如果该预制件存在多个也会一起删除 * @param prefabPath 预制路径 - * @param isDestroy 移除后是否释放 */ - remove(prefabPath: string, isDestroy?: boolean): void { - let release: any = undefined; - if (isDestroy !== undefined) release = isDestroy; + remove(prefabPath: string): void { + let release: boolean = true; // 界面移出舞台 - const uip = this.ui_nodes.get(prefabPath); - if (uip) { + const state = this.ui_nodes.get(prefabPath); + if (state) { // 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面 - if (release === undefined) { - release = uip.config.destroy !== undefined ? uip.config.destroy : true; - } + release = state.config.destroy !== undefined ? state.config.destroy : true; // 不释放界面,缓存起来待下次使用 if (release === false) { - this.ui_cache.set(uip.config.prefab, uip); + this.ui_cache.set(state.config.prefab, state); } - const node = uip.node; + const node = state.node; const comp = node.getComponent(LayerUIElement)!; comp.remove(release); } - // 验证是否删除后台缓存界面 - if (release === true) this.removeCache(prefabPath); + // 清理界面缓存 + const cache = this.ui_cache.get(prefabPath); + if (cache) { + // 验证是否删除后台缓存界面 + if (release) this.removeCache(prefabPath); + } } /** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */ private removeCache(prefabPath: string) { let vp = this.ui_cache.get(prefabPath); if (vp) { - this.onCloseWindow(vp); + this.uiClose(vp); this.ui_cache.delete(prefabPath); const node = vp.node; const comp = node.getComponent(LayerUIElement)!; @@ -177,6 +186,12 @@ export class LayerUI extends Node { } } + /** 显示界面 */ + show(prefabPath: string) { + const vp = this.ui_nodes.get(prefabPath); + if (vp) vp.node.parent = this; + } + /** * 根据预制路径获取已打开界面的节点对象 * @param prefabPath 预制路径 @@ -204,13 +219,13 @@ export class LayerUI extends Node { const length = this.ui_nodes.array.length - 1; for (let i = length; i >= 0; i--) { const uip = this.ui_nodes.array[i]; - this.remove(uip.config.prefab, isDestroy); + this.remove(uip.config.prefab); } this.ui_nodes.clear(); // 清除缓存中的界面 if (isDestroy) { - this.ui_cache.forEach((value: UIParams, prefabPath: string) => { + this.ui_cache.forEach((value: UIState, prefabPath: string) => { this.removeCache(prefabPath); }); } diff --git a/assets/core/gui/layer/LayerUIElement.ts b/assets/core/gui/layer/LayerUIElement.ts index 19e3131..f158fd8 100644 --- a/assets/core/gui/layer/LayerUIElement.ts +++ b/assets/core/gui/layer/LayerUIElement.ts @@ -18,11 +18,9 @@ const { ccclass } = _decorator; @ccclass('LayerUIElement') export class LayerUIElement extends Component { /** 视图参数 */ - params: UIParams = null!; + state: UIState = null!; /** 关闭窗口之前 */ - onCloseWindowBefore: Function = null!; - /** 界面关闭回调 - 包括关闭动画播放完(辅助框架内存业务流程使用) */ - private onCloseWindow: Function = null!; + onClose: Function = null!; /** 添加界面且界面设置到父节点之前 */ add(): Promise { @@ -32,7 +30,7 @@ export class LayerUIElement extends Component { const component: any = this.node.components[i]; const func = component[EventOnAdded]; if (func) { - if (await func.call(component, this.params.params) == false) { + if (await func.call(component, this.state.params.data) == false) { resolve(false); return; } @@ -40,8 +38,8 @@ export class LayerUIElement extends Component { } // 触发外部窗口显示前的事件(辅助实现自定义动画逻辑) - if (typeof this.params.callbacks.onAdded === "function") { - this.params.callbacks.onAdded(this.node, this.params.params); + if (typeof this.state.params.onAdded === "function") { + this.state.params.onAdded(this.node, this.state.params.data); } resolve(true); @@ -49,14 +47,14 @@ export class LayerUIElement extends Component { } /** 删除节点,该方法只能调用一次,将会触发onBeforeRemoved回调 */ - remove(isDestroy?: boolean) { - if (this.params.valid) { + remove(isDestroy: boolean) { + if (this.state.valid) { // 触发窗口移除舞台之前事件 - this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.params.params); + this.applyComponentsFunction(this.node, EventOnBeforeRemove, this.state.params.data); // 通知外部对象窗口组件上移除之前的事件(关闭窗口前的关闭动画处理) - if (typeof this.params.callbacks.onBeforeRemove === "function") { - this.params.callbacks.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy)); + if (typeof this.state.params.onBeforeRemove === "function") { + this.state.params.onBeforeRemove(this.node, this.onBeforeRemoveNext.bind(this, isDestroy)); } else { this.onBeforeRemoveNext(isDestroy); @@ -68,28 +66,26 @@ export class LayerUIElement extends Component { } /** 窗口关闭前动画处理完后的回调方法,主要用于释放资源 */ - private onBeforeRemoveNext(isDestroy?: boolean) { - this.onCloseWindowBefore && this.onCloseWindowBefore(); - this.removed(this.params, isDestroy); - } - - /** 窗口组件中触发移除事件与释放窗口对象 */ - private removed(uip: UIParams, isDestroy?: boolean) { - uip.valid = false; + private onBeforeRemoveNext(isDestroy: boolean) { + this.state.valid = false; - if (uip.callbacks && typeof uip.callbacks.onRemoved === "function") { - uip.callbacks.onRemoved(this.node, uip.params); + if (this.state.params && typeof this.state.params.onRemoved === "function") { + this.state.params.onRemoved(this.node, this.state.params.data); } - // 界面移除舞台事件 - this.onCloseWindow && this.onCloseWindow(uip); + // 关闭动画播放完后,界面移除舞台 + //@ts-ignore + this.node.parent.uiClose(this.state); + + // 关闭动画播放完后,界面移除舞台事件 + this.onClose && this.onClose(); if (isDestroy) { // 释放界面显示对象 this.node.destroy(); // 释放界面相关资源 - oops.res.release(uip.config.prefab, uip.config.bundle); + oops.res.release(this.state.config.prefab, this.state.config.bundle); // oops.log.logView(`【界面管理】释放【${uip.config.prefab}】界面资源`); } @@ -98,7 +94,7 @@ export class LayerUIElement extends Component { } // 触发窗口组件上窗口移除之后的事件 - this.applyComponentsFunction(this.node, EventOnRemoved, this.params.params); + this.applyComponentsFunction(this.node, EventOnRemoved, this.state.params.data); } private applyComponentsFunction(node: Node, funName: string, params: any) { @@ -112,38 +108,33 @@ export class LayerUIElement extends Component { } onDestroy() { - this.params = null!; - this.onCloseWindowBefore = null!; - this.onCloseWindow = null!; + this.state = null!; + this.onClose = null!; } } /** 本类型仅供gui模块内部使用,请勿在功能逻辑中使用 */ -export class UIParams { +export class UIState { /** 界面唯一编号 */ uiid: string = null!; /** 界面配置 */ config: UIConfig = null!; - /** 传递给打开界面的参数 */ - params: any = null!; /** 窗口事件 */ - callbacks: UICallbacks = null!; + params: UIParam = null!; /** 是否在使用状态 */ valid: boolean = true; /** 界面根节点 */ node: Node = null!; } -/** 界面关闭参数 */ -export interface UIRemove { - /** 关闭是否释放资源内存 */ - isDestroy?: boolean; - /** 界面动画播放完关闭事件 */ - onRemoved?: Function; -} +/*** 界面打开参数 */ +export interface UIParam { + /** 自定义传递参数 */ + data?: any; + + /** 是否开启预加载(默认不开启 - 开启后加载完不显示界面) */ + preload?: boolean; -/*** 界面回调参数对象定义 */ -export interface UICallbacks { /** * 节点添加到层级以后的回调 * @param node 当前界面节点 @@ -151,13 +142,6 @@ export interface UICallbacks { */ onAdded?: (node: Node, params: any) => void, - /** - * 窗口节点 destroy 之后回调 - * @param node 当前界面节点 - * @param params 外部传递参数 - */ - onRemoved?: (node: Node | null, params: any) => void, - /** * 如果指定onBeforeRemoved,则next必须调用,否则节点不会被正常删除。 * @@ -167,6 +151,10 @@ export interface UICallbacks { */ onBeforeRemove?: (node: Node, next: Function) => void, - /** 网络异常时,窗口加载失败回调 */ - onLoadFailure?: () => void; + /** + * 窗口节点 destroy 之后回调 + * @param node 当前界面节点 + * @param params 外部传递参数 + */ + onRemoved?: (node: Node, params: any) => void } \ No newline at end of file diff --git a/assets/core/gui/layer/UIConfig.ts b/assets/core/gui/layer/UIConfig.ts index 344c4d7..d736757 100644 --- a/assets/core/gui/layer/UIConfig.ts +++ b/assets/core/gui/layer/UIConfig.ts @@ -39,7 +39,7 @@ export interface UIConfig { vacancy?: boolean, /** 是否打开窗口后显示背景遮罩(默认关闭) */ mask?: boolean; - /** 是否启动真机安全区域显示 */ + /** 是否启动真机安全区域显示(默认关闭) */ safeArea?: boolean; /** 界面弹出时的节点排序索引 */ siblingIndex?: number; diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index e2738b5..3320319 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -5,7 +5,6 @@ * @LastEditTime: 2022-09-06 17:20:51 */ -import { UIRemove } from '../../core/gui/layer/LayerUIElement'; import { ecs } from '../../libs/ecs/ECS'; import { ECSModel } from '../../libs/ecs/ECSModel'; import { GameComponent } from './GameComponent'; @@ -43,13 +42,13 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { tid: number = -1; /** 从父节点移除自己 */ - remove(params?: UIRemove) { + remove() { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.removeGui(this.ent, cct, params); + ModuleUtil.removeGui(this.ent, cct); } else { - console.error(`组件 ${this.name} 移除失败,实体不存在`); + console.error(`组件 ${this.name} 移除失败,组件未注册`); } } diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index e5557a1..fa9c9c2 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -5,7 +5,6 @@ * @LastEditTime: 2022-09-06 17:22:05 */ -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'; @@ -55,13 +54,13 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { tid: number = -1; /** 从父节点移除自己 */ - remove(params?: UIRemove) { + remove() { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.removeGui(this.ent, cct, params); + ModuleUtil.removeGui(this.ent, cct); } else { - console.error(`组件 ${this.name} 移除失败,实体不存在`); + console.error(`组件 ${this.name} 移除失败,组件未注册`); } } diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 0b1a041..6f3410f 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -11,7 +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 { LayerUIElement } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; const { ccclass } = _decorator; @@ -483,18 +483,10 @@ export class GameComponent extends Component { //#endregion /** 移除自己 */ - remove(params?: UIRemove) { - if (params == null) { - params = { isDestroy: true }; - } - else { - if (params.isDestroy == null) params.isDestroy = true; - } - + remove() { const comp = this.node.getComponent(LayerUIElement); if (comp) { - if (params.onRemoved) comp.onCloseWindowBefore = params.onRemoved; - oops.gui.removeByNode(this.node, params.isDestroy); + oops.gui.removeByNode(this.node); } } diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/ModuleUtil.ts index 187ed7c..c2dbc53 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/ModuleUtil.ts @@ -2,8 +2,7 @@ import { Node, __private } from "cc"; import { oops } from "../../core/Oops"; import { resLoader } from "../../core/common/loader/ResLoader"; import { gui } from "../../core/gui/Gui"; -import { Uiid } from "../../core/gui/layer/LayerEnum"; -import { LayerUIElement, UICallbacks, UIRemove } from "../../core/gui/layer/LayerUIElement"; +import { LayerUIElement, UIParam } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; import { ecs } from "../../libs/ecs/ECS"; import { CompType } from "../../libs/ecs/ECSModel"; @@ -17,29 +16,26 @@ export class ModuleUtil { * 异步添加视图层组件 * @param ent 模块实体 * @param ctor 界面逻辑组件 - * @param uiArgs 界面参数 - * @param anim 界面打开与关闭动画 + * @param params 界面参数 * @returns 界面节点 */ - static addGui(ent: ecs.Entity, ctor: ECSCtor, uiArgs?: any, anim?: UICallbacks): 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); - if (anim && anim.onAdded) anim.onAdded(node, params); - resolve(node); - }, - onLoadFailure: () => { - if (anim && anim.onLoadFailure) anim.onLoadFailure(); - resolve(null); - } - }; - + static addGui(ent: ecs.Entity, ctor: ECSCtor, params?: UIParam): Promise { + return new Promise(async (resolve, reject) => { //@ts-ignore const key = ctor[gui.internal.GUI_KEY]; if (key) { - oops.gui.open(key, uiArgs, uic); + if (params == null) { + params = { preload: true }; + } + else { + params.preload = true; + } + + let node = await oops.gui.open(key, params); + const comp = node.getComponent(ctor) as ecs.Comp; + ent.add(comp); + oops.gui.show(key); + resolve(node); } else { console.error(`${key} 界面组件未使用 gui.register 注册`); @@ -49,18 +45,11 @@ export class ModuleUtil { /** * 业务实体上移除界面组件 - * @param ent 模块实体 - * @param ctor 界面逻辑组件 - * @param params 界面关闭参数 + * @param ent 模块实体 + * @param ctor 界面逻辑组件 + * @param params 界面关闭参数 */ - static removeGui(ent: ecs.Entity, ctor: CompType, params?: UIRemove) { - if (params == null) { - params = { isDestroy: true }; - } - else { - if (params.isDestroy == null) params.isDestroy = true; - } - + static removeGui(ent: ecs.Entity, ctor: CompType) { //@ts-ignore const key = ctor[gui.internal.GUI_KEY]; if (key) { @@ -72,16 +61,14 @@ export class ModuleUtil { const comp = node.getComponent(LayerUIElement); if (comp) { - comp.onCloseWindowBefore = () => { - if (params.isDestroy) ent.remove(ctor); - if (params.onRemoved) params.onRemoved(); + comp.onClose = () => { + if (comp.state.config.destroy) ent.remove(ctor); }; - oops.gui.remove(key, params.isDestroy); + oops.gui.remove(key); } } else { - if (params.isDestroy) ent.remove(ctor); - if (params.onRemoved) params.onRemoved(); + ent.remove(ctor); } } @@ -99,77 +86,4 @@ export class ModuleUtil { ent.add(comp); node.parent = parent; } - - //#region deprecated - /** - * 添加界面组件 - * @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 = { - onAdded: (node: Node, params: any) => { - const comp = node.getComponent(ctor) as ecs.Comp; - //@ts-ignore - if (!ent.has(ctor)) ent.add(comp); - } - }; - oops.gui.open(uiId, uiArgs, uic); - } - - /** - * 异步添加视图层组件 - * @param ent 模块实体 - * @param ctor 界面逻辑组件 - * @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) => { - const uic: UICallbacks = { - onAdded: (node: Node, params: any) => { - const comp = node.getComponent(ctor) as ecs.Comp; - ent.add(comp); - resolve(node); - }, - onLoadFailure: () => { - resolve(null); - } - }; - oops.gui.open(uiId, uiArgs, uic); - }); - } - - /** - * 业务实体上移除界面组件 - * @param ent 模块实体 - * @param ctor 界面逻辑组件 - * @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); - if (!node) { - if (onRemoved) onRemoved(); - return; - } - - const comp = node.getComponent(LayerUIElement); - if (comp) { - comp.onCloseWindowBefore = () => { - // 移除ECS显示组件 - if (isDestroy) ent.remove(ctor, isDestroy); - if (onRemoved) onRemoved(); - }; - oops.gui.remove(uiId, isDestroy); - } - } - //#endregion } \ No newline at end of file -- Gitee From 17ad6253aea5039351212620cffd7f822d14c80b Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 11 Sep 2025 09:17:49 +0800 Subject: [PATCH 09/37] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerDialog.ts | 4 ++-- assets/core/gui/layer/LayerPopup.ts | 19 ++++++++++++++----- assets/core/gui/layer/LayerUI.ts | 6 +++--- assets/core/gui/layer/LayerUIElement.ts | 2 +- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assets/core/gui/layer/LayerDialog.ts b/assets/core/gui/layer/LayerDialog.ts index bc80767..6ca32b6 100644 --- a/assets/core/gui/layer/LayerDialog.ts +++ b/assets/core/gui/layer/LayerDialog.ts @@ -59,8 +59,8 @@ export class LayerDialog extends LayerPopUp { }); } - protected uiClose(state: UIState) { - super.uiClose(state); + protected closeUi(state: UIState) { + super.closeUi(state); setTimeout(this.next.bind(this), 0); } diff --git a/assets/core/gui/layer/LayerPopup.ts b/assets/core/gui/layer/LayerPopup.ts index 70c3479..defd693 100644 --- a/assets/core/gui/layer/LayerPopup.ts +++ b/assets/core/gui/layer/LayerPopup.ts @@ -25,15 +25,24 @@ export class LayerPopUp extends LayerUI { } private onChildAdded(child: Node) { - if (this.mask) this.mask.setSiblingIndex(this.children.length - 2); + this.mask.setSiblingIndex(this.children.length - 2); } private onChildRemoved(child: Node) { - if (this.mask) this.mask.setSiblingIndex(this.children.length - 2); + this.mask.setSiblingIndex(this.children.length - 2); } protected uiInit(state: UIState): Promise { return new Promise(async (resolve) => { + // 背景半透明遮罩 + if (this.mask == null) { + this.mask = ViewUtil.createPrefabNode(PromptResType.Mask); + this.mask.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); + + this.black = this.mask.addComponent(BlockInputEvents); + this.black.enabled = false; + } + const r = await super.uiInit(state); if (r) { // 界面加载完成显示时,启动触摸非窗口区域关闭 @@ -46,8 +55,8 @@ export class LayerPopUp extends LayerUI { }); } - protected uiClose(state: UIState) { - super.uiClose(state); + protected closeUi(state: UIState) { + super.closeUi(state); // 界面关闭后,关闭触摸事件阻挡、关闭触摸非窗口区域关闭、关闭遮罩 this.closeBlack(); @@ -57,7 +66,7 @@ export class LayerPopUp extends LayerUI { protected closeBlack() { // 所有弹窗关闭后,关闭事件阻挡功能 if (this.ui_nodes.size == 0) { - if (this.black) this.black.enabled = false; + this.black.enabled = false; this.closeVacancyRemove(); } this.closeMask(); diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index bb93ccb..f3aec98 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -132,13 +132,13 @@ export class LayerUI extends Node { } /** 窗口关闭事件 */ - protected uiClose(state: UIState) { + protected closeUi(state: UIState) { this.ui_nodes.delete(state.config.prefab); } /** 打开窗口失败逻辑 */ protected failure(state: UIState) { - this.uiClose(state); + this.closeUi(state); this.onOpenFailure && this.onOpenFailure(); } @@ -177,7 +177,7 @@ export class LayerUI extends Node { private removeCache(prefabPath: string) { let vp = this.ui_cache.get(prefabPath); if (vp) { - this.uiClose(vp); + this.closeUi(vp); this.ui_cache.delete(prefabPath); const node = vp.node; const comp = node.getComponent(LayerUIElement)!; diff --git a/assets/core/gui/layer/LayerUIElement.ts b/assets/core/gui/layer/LayerUIElement.ts index f158fd8..7ad9a76 100644 --- a/assets/core/gui/layer/LayerUIElement.ts +++ b/assets/core/gui/layer/LayerUIElement.ts @@ -75,7 +75,7 @@ export class LayerUIElement extends Component { // 关闭动画播放完后,界面移除舞台 //@ts-ignore - this.node.parent.uiClose(this.state); + this.node.parent.closeUi(this.state); // 关闭动画播放完后,界面移除舞台事件 this.onClose && this.onClose(); -- Gitee From 51ec98f2931e5ad59c6277a71e1f2ab46f9a63a0 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 11 Sep 2025 09:33:04 +0800 Subject: [PATCH 10/37] =?UTF-8?q?=E4=BC=98=E5=8C=96=E3=80=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerDialog.ts | 8 ++------ assets/core/gui/layer/LayerManager.ts | 2 +- assets/core/gui/layer/LayerUI.ts | 7 ++++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/assets/core/gui/layer/LayerDialog.ts b/assets/core/gui/layer/LayerDialog.ts index 6ca32b6..f9b9ed0 100644 --- a/assets/core/gui/layer/LayerDialog.ts +++ b/assets/core/gui/layer/LayerDialog.ts @@ -36,11 +36,7 @@ export class LayerDialog extends LayerPopUp { return new Promise(async (resolve, reject) => { // 控制同一时间只能显示一个模式窗口 if (this.ui_nodes.size > 0) { - this.params.push({ - uiid: uiid, - config: config, - params: params - }); + this.params.push({ uiid: uiid, config: config, params: params }); resolve(this.current); } else { @@ -54,7 +50,7 @@ export class LayerDialog extends LayerPopUp { private showDialog(uiid: string, config: UIConfig, param?: UIParam): Promise { return new Promise(async (resolve, reject) => { let state = this.initUIConfig(uiid, config, param); - let node = await this.load(state, config.bundle); + let node = await this.load(state); resolve(node); }); } diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index 3be745e..3286ac8 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -215,7 +215,7 @@ export class LayerManager { } }; - oops.gui.open(UIID.Loading, null, uic); + oops.gui.open(UIID.Loading); */ open(uiid: Uiid, param?: UIParam): Promise { return new Promise(async (resolve, reject) => { diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index f3aec98..2c24665 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -27,6 +27,7 @@ export class LayerUI extends Node { /** * 添加一个预制件节点到层容器中,该方法将返回一个唯一`uuid`来标识该操作节点 + * @param uiid 窗口唯一标识 * @param config 界面配置数据 * @param params 自定义参数 * @returns ture为成功,false为失败 @@ -40,7 +41,7 @@ export class LayerUI extends Node { // 检查缓存中是否存界面 let state = this.initUIConfig(uiid, config, params); - await this.load(state, config.bundle); + await this.load(state); resolve(state.node); }); } @@ -70,13 +71,13 @@ export class LayerUI extends Node { * @param state 显示参数 * @param bundle 远程资源包名,如果为空就是默认本地资源包 */ - protected async load(state: UIState, bundle: string = resLoader.defaultBundleName): Promise { + protected async load(state: UIState): Promise { return new Promise(async (resolve, reject) => { // 加载界面资源超时提示 let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); if (state.node == null) { // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 - const res = await resLoader.loadAsync(bundle, state.config.prefab, Prefab); + const res = await resLoader.loadAsync(state.config.bundle!, state.config.prefab, Prefab); if (res) { state.node = instantiate(res); -- Gitee From 0a9112ea6444af4e2535ab687d062563e7ab3bd3 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 11 Sep 2025 15:39:38 +0800 Subject: [PATCH 11/37] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0=20ECS=20=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E5=AE=9E=E4=BD=93=20CCEntity=20=E5=AF=B9=E8=B1=A1=202?= =?UTF-8?q?.=20=E5=88=A0=E9=99=A4=20ModuleUtil.ts=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E5=8A=9F=E8=83=BD=E7=A7=BB=E7=BD=AE=E5=88=B0=20CCEnti?= =?UTF-8?q?ty=20=E5=AF=B9=E8=B1=A1=E4=B8=AD=EF=BC=8C=E7=AE=80=E5=8C=96=20A?= =?UTF-8?q?pi=20=E7=9A=84=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCComp.ts | 8 +-- .../common/{ModuleUtil.ts => CCEntity.ts} | 53 +++++++++---------- .../{ModuleUtil.ts.meta => CCEntity.ts.meta} | 2 +- assets/module/common/CCVMParentComp.ts | 8 +-- 4 files changed, 34 insertions(+), 37 deletions(-) rename assets/module/common/{ModuleUtil.ts => CCEntity.ts} (74%) rename assets/module/common/{ModuleUtil.ts.meta => CCEntity.ts.meta} (70%) diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index 3320319..f37a178 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -7,11 +7,11 @@ import { ecs } from '../../libs/ecs/ECS'; import { ECSModel } from '../../libs/ecs/ECSModel'; +import { CCEntity } from './CCEntity'; import { GameComponent } from './GameComponent'; -import { ModuleUtil } from './ModuleUtil'; /** - * 游戏显示对象组件 + * ECS 游戏显示对象组件 * * 功能介绍: * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 @@ -38,14 +38,14 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: ecs.Entity; + ent!: CCEntity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.removeGui(this.ent, cct); + this.ent.removeUi(cct); } else { console.error(`组件 ${this.name} 移除失败,组件未注册`); diff --git a/assets/module/common/ModuleUtil.ts b/assets/module/common/CCEntity.ts similarity index 74% rename from assets/module/common/ModuleUtil.ts rename to assets/module/common/CCEntity.ts index c2dbc53..d7f3b05 100644 --- a/assets/module/common/ModuleUtil.ts +++ b/assets/module/common/CCEntity.ts @@ -1,8 +1,8 @@ -import { Node, __private } from "cc"; -import { oops } from "../../core/Oops"; +import { __private, Node } from "cc"; import { resLoader } from "../../core/common/loader/ResLoader"; import { gui } from "../../core/gui/Gui"; import { LayerUIElement, UIParam } from "../../core/gui/layer/LayerUIElement"; +import { oops } from "../../core/Oops"; import { ViewUtil } from "../../core/utils/ViewUtil"; import { ecs } from "../../libs/ecs/ECS"; import { CompType } from "../../libs/ecs/ECSModel"; @@ -11,15 +11,29 @@ import { CCVMParentComp } from "./CCVMParentComp"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; -export class ModuleUtil { +/** ECS 游戏模块实体 */ +export class CCEntity extends ecs.Entity { + /** + * 通过资源内存中获取预制上的组件添加到ECS实体中 + * @param ctor 界面逻辑组件 + * @param parent 显示对象父级 + * @param path 显示资源地址 + * @param bundleName 资源包名称 + */ + addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { + const node = ViewUtil.createPrefabNode(path, bundleName); + const comp = node.getComponent(ctor)!; + this.add(comp); + node.parent = parent; + } + /** - * 异步添加视图层组件 - * @param ent 模块实体 + * 添加视图层组件 * @param ctor 界面逻辑组件 * @param params 界面参数 * @returns 界面节点 */ - static addGui(ent: ecs.Entity, ctor: ECSCtor, params?: UIParam): Promise { + addUi(ctor: ECSCtor, params?: UIParam): Promise { return new Promise(async (resolve, reject) => { //@ts-ignore const key = ctor[gui.internal.GUI_KEY]; @@ -33,7 +47,7 @@ export class ModuleUtil { let node = await oops.gui.open(key, params); const comp = node.getComponent(ctor) as ecs.Comp; - ent.add(comp); + this.add(comp); oops.gui.show(key); resolve(node); } @@ -44,12 +58,10 @@ export class ModuleUtil { } /** - * 业务实体上移除界面组件 - * @param ent 模块实体 + * 移除视图层组件 * @param ctor 界面逻辑组件 - * @param params 界面关闭参数 */ - static removeGui(ent: ecs.Entity, ctor: CompType) { + removeUi(ctor: CompType) { //@ts-ignore const key = ctor[gui.internal.GUI_KEY]; if (key) { @@ -62,28 +74,13 @@ export class ModuleUtil { const comp = node.getComponent(LayerUIElement); if (comp) { comp.onClose = () => { - if (comp.state.config.destroy) ent.remove(ctor); + if (comp.state.config.destroy) this.remove(ctor); }; oops.gui.remove(key); } } else { - ent.remove(ctor); + this.remove(ctor); } } - - /** - * 通过资源内存中获取预制上的组件添加到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; - } } \ No newline at end of file diff --git a/assets/module/common/ModuleUtil.ts.meta b/assets/module/common/CCEntity.ts.meta similarity index 70% rename from assets/module/common/ModuleUtil.ts.meta rename to assets/module/common/CCEntity.ts.meta index 1a06125..7040995 100644 --- a/assets/module/common/ModuleUtil.ts.meta +++ b/assets/module/common/CCEntity.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "52a6c740-3b9b-46c5-a784-d53a6b67954a", + "uuid": "59805570-9a5d-4894-aac0-14a60c895c74", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index fa9c9c2..9f6cbf4 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -8,10 +8,10 @@ import { ecs } from '../../libs/ecs/ECS'; import { ECSModel } from '../../libs/ecs/ECSModel'; import VMParent from '../../libs/model-view/VMParent'; -import { ModuleUtil } from './ModuleUtil'; +import { CCEntity } from './CCEntity'; /** - * 支持 MVVM 功能的游戏显示对象组件 + * 支持 MVVM 功能的 ECS 游戏显示对象组件 * * 使用方法: * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 @@ -50,14 +50,14 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: ecs.Entity; + ent!: CCEntity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; if (this.ent) { - ModuleUtil.removeGui(this.ent, cct); + this.ent.removeUi(cct); } else { console.error(`组件 ${this.name} 移除失败,组件未注册`); -- Gitee From 1feb30628f560f0d161677442149f113a54ae600 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 12 Sep 2025 09:25:24 +0800 Subject: [PATCH 12/37] =?UTF-8?q?=E4=BC=98=E5=8C=96Gui=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/Gui.ts | 6 ++ assets/core/gui/layer/LayerManager.ts | 18 +++++- assets/core/gui/layer/LayerPopup.ts | 12 +--- assets/core/gui/layer/LayerUI.ts | 60 ++++++++++--------- assets/core/gui/layer/LayerUIElement.ts | 4 -- assets/libs/gui/label/LabelTime.ts | 76 +++++++++++++++---------- assets/module/common/CCEntity.ts | 11 ++-- 7 files changed, 108 insertions(+), 79 deletions(-) diff --git a/assets/core/gui/Gui.ts b/assets/core/gui/Gui.ts index 96f64cc..7afdd97 100644 --- a/assets/core/gui/Gui.ts +++ b/assets/core/gui/Gui.ts @@ -17,6 +17,12 @@ export namespace gui { export namespace internal { /** 界面唯一标记变量名 */ export const GUI_KEY = "OOPS_GUI_KEY"; + + /** 获取界面唯一关键字 */ + export function getKey(ctor: any) { + return ctor[GUI_KEY]; + } + /** 获取界面组件配置 */ export function getConfig(key: string) { return configs[key]; diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index 3286ac8..6720350 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -1,5 +1,4 @@ import { Camera, Node, ResolutionPolicy, SafeArea, screen, view, warn } from "cc"; -import { resLoader } from "../../common/loader/ResLoader"; import { oops } from "../../Oops"; import { gui } from "../Gui"; import { LayerDialog } from "./LayerDialog"; @@ -260,6 +259,23 @@ export class LayerManager { } } + /** + * 清理指定界面的缓存 + * @param uiid 窗口唯一标识 + * @example + * oops.gui.removeCache(UIID.Loading); + */ + removeCache(uiid: Uiid) { + let info = this.getInfo(uiid); + let layer = this.uiLayers.get(info.config.layer); + if (layer) { + layer.removeCache(info.config.prefab); + } + else { + console.error(`移除编号为【${uiid}】的界面失败,界面层不存在`); + } + } + /** * 通过界面节点移除 * @param node 窗口节点 diff --git a/assets/core/gui/layer/LayerPopup.ts b/assets/core/gui/layer/LayerPopup.ts index defd693..1b5e12c 100644 --- a/assets/core/gui/layer/LayerPopup.ts +++ b/assets/core/gui/layer/LayerPopup.ts @@ -17,19 +17,13 @@ export class LayerPopUp extends LayerUI { /** 半透明遮罩资源 */ protected mask!: Node; - constructor(name: string) { - super(name); - - this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this); - this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this); - } - - private onChildAdded(child: Node) { + protected onChildAdded(child: Node) { this.mask.setSiblingIndex(this.children.length - 2); } - private onChildRemoved(child: Node) { + protected onChildRemoved(child: Node) { this.mask.setSiblingIndex(this.children.length - 2); + super.onChildRemoved(child); } protected uiInit(state: UIState): Promise { diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index 2c24665..14ee9fe 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -23,6 +23,20 @@ export class LayerUI extends Node { constructor(name: string) { super(name); LayerHelper.setFullScreen(this); + + this.on(Node.EventType.CHILD_ADDED, this.onChildAdded, this); + this.on(Node.EventType.CHILD_REMOVED, this.onChildRemoved, this); + } + + protected onChildAdded(child: Node) { + + } + + protected onChildRemoved(child: Node) { + const comp = child.getComponent(LayerUIElement); + if (comp) { + this.closeUi(comp.state); + } } /** @@ -74,8 +88,9 @@ export class LayerUI extends Node { protected async load(state: UIState): Promise { return new Promise(async (resolve, reject) => { // 加载界面资源超时提示 - let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); if (state.node == null) { + let timerId = setTimeout(this.onLoadingTimeoutGui, oops.config.game.loadingTimeoutGui); + // 优先加载配置的指定资源包中资源,如果没配置则加载默认资源包资源 const res = await resLoader.loadAsync(state.config.bundle!, state.config.prefab, Prefab); if (res) { @@ -92,14 +107,13 @@ export class LayerUI extends Node { console.warn(`路径为【${state.config.prefab}】的预制加载失败`); this.failure(state); } - } - // 关闭界面资源超时提示 - oops.gui.waitClose(); - clearTimeout(timerId); + // 关闭界面资源超时提示 + oops.gui.waitClose(); + clearTimeout(timerId); + } await this.uiInit(state); - resolve(state.node); }); } @@ -157,40 +171,30 @@ export class LayerUI extends Node { release = state.config.destroy !== undefined ? state.config.destroy : true; // 不释放界面,缓存起来待下次使用 - if (release === false) { - this.ui_cache.set(state.config.prefab, state); - } + if (release === false) this.ui_cache.set(state.config.prefab, state); - const node = state.node; - const comp = node.getComponent(LayerUIElement)!; + const comp = state.node.getComponent(LayerUIElement)!; comp.remove(release); } - // 清理界面缓存 - const cache = this.ui_cache.get(prefabPath); - if (cache) { - // 验证是否删除后台缓存界面 - if (release) this.removeCache(prefabPath); - } + // 验证是否删除后台缓存界面 + if (release) this.removeCache(prefabPath); } /** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */ - private removeCache(prefabPath: string) { - let vp = this.ui_cache.get(prefabPath); - if (vp) { - this.closeUi(vp); + removeCache(prefabPath: string) { + const state = this.ui_cache.get(prefabPath); + if (state) { this.ui_cache.delete(prefabPath); - const node = vp.node; - const comp = node.getComponent(LayerUIElement)!; + const comp = state.node.getComponent(LayerUIElement)!; comp.remove(true); - node.destroy(); } } /** 显示界面 */ show(prefabPath: string) { - const vp = this.ui_nodes.get(prefabPath); - if (vp) vp.node.parent = this; + const state = this.ui_nodes.get(prefabPath); + if (state) state.node.parent = this; } /** @@ -198,8 +202,8 @@ export class LayerUI extends Node { * @param prefabPath 预制路径 */ get(prefabPath: string): Node { - const vp = this.ui_nodes.get(prefabPath); - if (vp) return vp.node; + const state = this.ui_nodes.get(prefabPath); + if (state) return state.node; return null!; } diff --git a/assets/core/gui/layer/LayerUIElement.ts b/assets/core/gui/layer/LayerUIElement.ts index 7ad9a76..4fede83 100644 --- a/assets/core/gui/layer/LayerUIElement.ts +++ b/assets/core/gui/layer/LayerUIElement.ts @@ -73,10 +73,6 @@ export class LayerUIElement extends Component { this.state.params.onRemoved(this.node, this.state.params.data); } - // 关闭动画播放完后,界面移除舞台 - //@ts-ignore - this.node.parent.closeUi(this.state); - // 关闭动画播放完后,界面移除舞台事件 this.onClose && this.onClose(); diff --git a/assets/libs/gui/label/LabelTime.ts b/assets/libs/gui/label/LabelTime.ts index 7831f6d..e370c7f 100644 --- a/assets/libs/gui/label/LabelTime.ts +++ b/assets/libs/gui/label/LabelTime.ts @@ -1,32 +1,32 @@ import { Label, _decorator } from "cc"; +import { EDITOR } from "cc/env"; import { oops } from "../../../core/Oops"; import { EventMessage } from "../../../core/common/event/EventMessage"; import { TimeUtil } from "../../../core/utils/TimeUtils"; -import { EDITOR } from "cc/env"; const { ccclass, property, menu } = _decorator; /** 倒计时标签 */ @ccclass("LabelTime") -@menu('OopsFramework/Label/LabelTime (倒计时标签)') +@menu("OopsFramework/Label/LabelTime (倒计时标签)") export default class LabelTime extends Label { @property({ - tooltip: "到计时间总时间(单位秒)" + tooltip: "到计时间总时间(单位秒)", }) countDown: number = 1000; @property({ - tooltip: "天数数据格式化" + tooltip: "天数数据格式化", }) dayFormat: string = "{0} day"; @property({ - tooltip: "时间格式化" + tooltip: "时间格式化", }) timeFormat: string = "{0}:{1}:{2}"; @property({ - tooltip: "是否有00" + tooltip: "是否有00", }) zeroize: boolean = true; @@ -35,9 +35,9 @@ export default class LabelTime extends Label { }) paused: boolean = false; - private backStartTime: number = 0; // 进入后台开始时间 - private dateDisable!: boolean; // 时间能否由天数显示 - private result!: string; // 时间结果字符串 + private backStartTime: number = 0; // 进入后台开始时间 + private dateDisable!: boolean; // 时间能否由天数显示 + private result!: string; // 时间结果字符串 /** 每秒触发事件 */ onSecond: Function = null!; @@ -45,10 +45,9 @@ export default class LabelTime extends Label { onComplete: Function = null!; private replace(value: string, ...args: any): string { - return value.replace(/\{(\d+)\}/g, - function (m, i) { - return args[i]; - }); + return value.replace(/\{(\d+)\}/g, function (m, i) { + return args[i]; + }); } /** 格式化字符串 */ @@ -84,23 +83,15 @@ export default class LabelTime extends Label { if (date < 2) { df = df.replace("days", "day"); } - this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..." + this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..." } else { hours += date * 24; if (this.zeroize) { - this.result = this.replace( - this.timeFormat, - this.coverString(hours), - this.coverString(minutes), - this.coverString(seconds)); // 否则显示 "01:12:24" + this.result = this.replace(this.timeFormat, this.coverString(hours), this.coverString(minutes), this.coverString(seconds)); // 否则显示 "01:12:24" } else { - this.result = this.replace( - this.timeFormat, - hours, - minutes, - seconds); + this.result = this.replace(this.timeFormat, hours, minutes, seconds); } } this.string = this.result; @@ -108,8 +99,7 @@ export default class LabelTime extends Label { /** 个位数的时间数据将字符串补位 */ private coverString(value: number) { - if (value < 10) - return "0" + value; + if (value < 10) return "0" + value; return value.toString(); } @@ -123,7 +113,7 @@ export default class LabelTime extends Label { * @param second 倒计时时间(单位秒) */ setTime(second: number) { - this.countDown = second; // 倒计时,初始化显示字符串 + this.countDown = second; // 倒计时,初始化显示字符串 this.timing_end(); this.timing_start(); this.format(); @@ -140,15 +130,33 @@ export default class LabelTime extends Label { this.format(); } - start() { + onLoad() { if (!EDITOR) { oops.message.on(EventMessage.GAME_SHOW, this.onGameShow, this); oops.message.on(EventMessage.GAME_HIDE, this.onGameHide, this); } + } + + start() { + if (this.countDown <= 0) return; this.timing_start(); this.format(); } + onEnable() { + super.onEnable(); + if (!EDITOR) { + this.onGameShow(); + } + } + + onDisable() { + super.onDisable(); + if (!EDITOR) { + this.onGameHide(); + } + } + onDestroy() { if (!EDITOR) { oops.message.off(EventMessage.GAME_SHOW, this.onGameShow, this); @@ -175,6 +183,12 @@ export default class LabelTime extends Label { } private onScheduleSecond() { + if (this.countDown == 0) { + this.format(); + this.onScheduleComplete(); + return; + } + this.countDown--; this.format(); if (this.onSecond) this.onSecond(this.node); @@ -187,15 +201,17 @@ export default class LabelTime extends Label { private onScheduleComplete() { this.timing_end(); this.format(); + this.unschedule(this.onScheduleSecond); if (this.onComplete) this.onComplete(this.node); } /** 开始计时 */ - private timing_start() { + timing_start() { this.schedule(this.onScheduleSecond, 1); } - private timing_end() { + /** 关闭计时 */ + timing_end() { this.unscheduleAllCallbacks(); } } diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index d7f3b05..2e9b50c 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -35,8 +35,7 @@ export class CCEntity extends ecs.Entity { */ addUi(ctor: ECSCtor, params?: UIParam): Promise { return new Promise(async (resolve, reject) => { - //@ts-ignore - const key = ctor[gui.internal.GUI_KEY]; + const key = gui.internal.getKey(ctor); if (key) { if (params == null) { params = { preload: true }; @@ -62,8 +61,7 @@ export class CCEntity extends ecs.Entity { * @param ctor 界面逻辑组件 */ removeUi(ctor: CompType) { - //@ts-ignore - const key = ctor[gui.internal.GUI_KEY]; + const key = gui.internal.getKey(ctor); if (key) { const node = oops.gui.get(key); if (node == null) { @@ -73,9 +71,8 @@ export class CCEntity extends ecs.Entity { const comp = node.getComponent(LayerUIElement); if (comp) { - comp.onClose = () => { - if (comp.state.config.destroy) this.remove(ctor); - }; + // 处理界面关闭动画播放完成后,移除ECS组件,避免使用到组件实体数据还在动画播放时在使用导致的空对象问题 + comp.onClose = this.remove.bind(this, ctor); oops.gui.remove(key); } } -- Gitee From 5570f20913b54562e45c7181d0f6ab9f92b09137 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 12 Sep 2025 11:32:31 +0800 Subject: [PATCH 13/37] =?UTF-8?q?=E4=BF=AE=E5=A4=8DLayerPopup=E5=B1=82?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9D=9EGui=E6=A1=86=E6=9E=B6=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=9A=84=E8=8A=82=E7=82=B9=E6=97=B6=E7=9A=84=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerPopup.ts | 15 +++------------ assets/module/common/CCEntity.ts | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/assets/core/gui/layer/LayerPopup.ts b/assets/core/gui/layer/LayerPopup.ts index 1b5e12c..6ac6d15 100644 --- a/assets/core/gui/layer/LayerPopup.ts +++ b/assets/core/gui/layer/LayerPopup.ts @@ -18,25 +18,16 @@ export class LayerPopUp extends LayerUI { protected mask!: Node; protected onChildAdded(child: Node) { - this.mask.setSiblingIndex(this.children.length - 2); + this.mask && this.mask.setSiblingIndex(this.children.length - 2); } protected onChildRemoved(child: Node) { - this.mask.setSiblingIndex(this.children.length - 2); + this.mask && this.mask.setSiblingIndex(this.children.length - 2); super.onChildRemoved(child); } protected uiInit(state: UIState): Promise { return new Promise(async (resolve) => { - // 背景半透明遮罩 - if (this.mask == null) { - this.mask = ViewUtil.createPrefabNode(PromptResType.Mask); - this.mask.on(Node.EventType.TOUCH_END, this.onTouchEnd, this); - - this.black = this.mask.addComponent(BlockInputEvents); - this.black.enabled = false; - } - const r = await super.uiInit(state); if (r) { // 界面加载完成显示时,启动触摸非窗口区域关闭 @@ -60,7 +51,7 @@ export class LayerPopUp extends LayerUI { protected closeBlack() { // 所有弹窗关闭后,关闭事件阻挡功能 if (this.ui_nodes.size == 0) { - this.black.enabled = false; + if (this.black) this.black.enabled = false; this.closeVacancyRemove(); } this.closeMask(); diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index 2e9b50c..a4a3b2a 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -44,7 +44,7 @@ export class CCEntity extends ecs.Entity { params.preload = true; } - let node = await oops.gui.open(key, params); + const node = await oops.gui.open(key, params); const comp = node.getComponent(ctor) as ecs.Comp; this.add(comp); oops.gui.show(key); -- Gitee From b7f3d041220e878f0b9ce9610b487c21baf646e9 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 12 Sep 2025 15:38:24 +0800 Subject: [PATCH 14/37] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCComp.ts | 4 ++-- assets/module/common/CCVMParentComp.ts | 4 ++-- assets/module/common/GameComponent.ts | 6 +----- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index f37a178..afdcf77 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -38,13 +38,13 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: CCEntity; + ent!: ecs.Entity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; - if (this.ent) { + if (this.ent && this.ent instanceof CCEntity) { this.ent.removeUi(cct); } else { diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index 9f6cbf4..7a43c7d 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -50,13 +50,13 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: CCEntity; + ent!: ecs.Entity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; - if (this.ent) { + if (this.ent && this.ent instanceof CCEntity) { this.ent.removeUi(cct); } else { diff --git a/assets/module/common/GameComponent.ts b/assets/module/common/GameComponent.ts index 6f3410f..031ce00 100644 --- a/assets/module/common/GameComponent.ts +++ b/assets/module/common/GameComponent.ts @@ -11,7 +11,6 @@ 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 } from "../../core/gui/layer/LayerUIElement"; import { ViewUtil } from "../../core/utils/ViewUtil"; const { ccclass } = _decorator; @@ -484,10 +483,7 @@ export class GameComponent extends Component { /** 移除自己 */ remove() { - const comp = this.node.getComponent(LayerUIElement); - if (comp) { - oops.gui.removeByNode(this.node); - } + oops.gui.removeByNode(this.node); } protected onDestroy() { -- Gitee From a47498dcc1a868dd6f8759e1056e02c64fd44b6c Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 12 Sep 2025 18:10:00 +0800 Subject: [PATCH 15/37] =?UTF-8?q?CCEntity=E6=96=B0=E5=A2=9E=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=8D=95=E4=BE=8B=E5=AD=90=E5=AE=9E=E4=BD=93=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/gui/layer/LayerUI.ts | 12 +++-------- assets/core/gui/layer/UIConfig.ts | 2 +- assets/libs/ecs/ECSEntity.ts | 36 +++++++++++++++++++------------ assets/module/common/CCEntity.ts | 28 ++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/assets/core/gui/layer/LayerUI.ts b/assets/core/gui/layer/LayerUI.ts index 14ee9fe..c209c13 100644 --- a/assets/core/gui/layer/LayerUI.ts +++ b/assets/core/gui/layer/LayerUI.ts @@ -162,26 +162,20 @@ export class LayerUI extends Node { * @param prefabPath 预制路径 */ remove(prefabPath: string): void { - let release: boolean = true; - - // 界面移出舞台 const state = this.ui_nodes.get(prefabPath); if (state) { - // 优先使用参数中控制的释放条件,如果未传递参数则用配置中的释放条件,默认不缓存关闭的界面 - release = state.config.destroy !== undefined ? state.config.destroy : true; + let release: boolean = state.config.destroy!; // 不释放界面,缓存起来待下次使用 if (release === false) this.ui_cache.set(state.config.prefab, state); + // 界面移出舞台 const comp = state.node.getComponent(LayerUIElement)!; comp.remove(release); } - - // 验证是否删除后台缓存界面 - if (release) this.removeCache(prefabPath); } - /** 删除缓存的界面,当缓存界面被移除舞台时,可通过此方法删除缓存界面 */ + /** 删除缓存的界面,当调用 remove 移除舞台时,可通过此方法删除缓存界面 */ removeCache(prefabPath: string) { const state = this.ui_cache.get(prefabPath); if (state) { diff --git a/assets/core/gui/layer/UIConfig.ts b/assets/core/gui/layer/UIConfig.ts index d736757..7babb75 100644 --- a/assets/core/gui/layer/UIConfig.ts +++ b/assets/core/gui/layer/UIConfig.ts @@ -31,7 +31,7 @@ export interface UIConfig { layer: string; /** 预制资源相对路径 */ prefab: string; - /** 是否自动施放(默认不自动释放) */ + /** 是否自动施放(默认自动释放) */ destroy?: boolean; /** -----弹窗属性----- */ diff --git a/assets/libs/ecs/ECSEntity.ts b/assets/libs/ecs/ECSEntity.ts index 09511c9..e6c2d4f 100644 --- a/assets/libs/ecs/ECSEntity.ts +++ b/assets/libs/ecs/ECSEntity.ts @@ -81,22 +81,30 @@ export class ECSEntity { this._parent = value; } - private _children: Map | null = null; - /** 子实体集合 */ - get children(): Map { - if (this._children == null) { - this._children = new Map(); - } - return this._children; + /** 子实体 */ + private childs: Map = null!; + + /** 获取子实体 */ + getChild(eid: number) { + return this.childs.get(eid) as T; } /** * 添加子实体 * @param entity 被添加的实体对象 + * @returns 子实体的唯一编号, -1表示添加失败 */ - addChild(entity: ECSEntity) { + addChild(entity: ECSEntity): number { + if (this.childs == null) this.childs = new Map(); + + if (this.childs.has(entity.eid)) { + console.warn(`子实体${entity.name}已存在`); + return -1; + } + entity._parent = this; - this.children.set(entity.eid, entity); + this.childs.set(entity.eid, entity); + return entity.eid; } /** @@ -106,10 +114,10 @@ export class ECSEntity { * @returns */ removeChild(entity: ECSEntity, isDestroy = true) { - if (this.children == null) return; + if (this.childs == null) return; entity.parent = null; - this.children.delete(entity.eid); + this.childs.delete(entity.eid); if (isDestroy) entity.destroy(); } @@ -275,11 +283,11 @@ export class ECSEntity { } // 移除模块上所有子模块 - if (this._children) { - this._children.forEach(e => { + if (this.childs) { + this.childs.forEach(e => { this.removeChild(e); }); - this._children = null; + this.childs = null!; } // 移除实体上所有组件 diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index a4a3b2a..c0299e8 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -5,6 +5,7 @@ import { LayerUIElement, UIParam } from "../../core/gui/layer/LayerUIElement"; import { oops } from "../../core/Oops"; import { ViewUtil } from "../../core/utils/ViewUtil"; import { ecs } from "../../libs/ecs/ECS"; +import { ECSEntity } from "../../libs/ecs/ECSEntity"; import { CompType } from "../../libs/ecs/ECSModel"; import { CCComp } from "./CCComp"; import { CCVMParentComp } from "./CCVMParentComp"; @@ -13,6 +14,33 @@ export type ECSCtor = __private.__types_globals__Constructor /** ECS 游戏模块实体 */ export class CCEntity extends ecs.Entity { + /** 单例子实体 */ + private singletons: Map = null!; + + /** 添加单例子实体 */ + addChildSingleton(cls: any): T { + if (this.singletons == null) this.singletons = new Map(); + + let entity = cls.create() + this.singletons.set(cls, entity); + this.addChild(entity); + return entity as T; + } + + /** 获取单例子实体 */ + getChildSingleton(cls: any): T { + return this.singletons.get(cls) as T; + } + + /** 移除单例子实体 */ + removeChildSingleton(cls: any) { + let entity = this.singletons.get(cls); + if (entity) { + this.singletons.delete(cls); + this.removeChild(entity); + } + } + /** * 通过资源内存中获取预制上的组件添加到ECS实体中 * @param ctor 界面逻辑组件 -- Gitee From 32a11ae3b06363cb9da0e3a106cf50f3d3589e0b Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 09:57:14 +0800 Subject: [PATCH 16/37] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=A1=8C=E4=B8=BA?= =?UTF-8?q?=E6=A0=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/libs/behavior-tree/BTreeNode.ts | 18 +++++++++--------- assets/libs/behavior-tree/BehaviorTree.ts | 14 +++++++------- assets/libs/behavior-tree/BranchNode.ts | 14 +++++++------- assets/libs/behavior-tree/Decorator.ts | 8 ++++---- assets/libs/behavior-tree/Selector.ts | 4 ++-- assets/libs/behavior-tree/Sequence.ts | 4 ++-- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/assets/libs/behavior-tree/BTreeNode.ts b/assets/libs/behavior-tree/BTreeNode.ts index debef83..0932554 100644 --- a/assets/libs/behavior-tree/BTreeNode.ts +++ b/assets/libs/behavior-tree/BTreeNode.ts @@ -10,35 +10,35 @@ import { IControl } from './IControl'; export abstract class BTreeNode implements IControl { protected _control!: IControl; - public title: string; + title: string; - public constructor() { + constructor() { this.title = this.constructor.name; } - public start(blackboard?: any) { + start(blackboard?: any) { } - public end(blackboard?: any) { + end(blackboard?: any) { } - public abstract run(blackboard?: any): void; + abstract run(blackboard?: any): void; - public setControl(control: IControl) { + setControl(control: IControl) { this._control = control; } - public running(blackboard?: any) { + running(blackboard?: any) { this._control.running(this); } - public success() { + success() { this._control.success(); } - public fail() { + fail() { this._control.fail(); } } \ No newline at end of file diff --git a/assets/libs/behavior-tree/BehaviorTree.ts b/assets/libs/behavior-tree/BehaviorTree.ts index 55f78dc..d7beb52 100644 --- a/assets/libs/behavior-tree/BehaviorTree.ts +++ b/assets/libs/behavior-tree/BehaviorTree.ts @@ -17,7 +17,7 @@ export class BehaviorTree implements IControl { private _blackboard: any; /** 是否已开始执行 */ - public get started(): boolean { + get started(): boolean { return this._started; } @@ -26,7 +26,7 @@ export class BehaviorTree implements IControl { * @param node 根节点 * @param blackboard 外部参数对象 */ - public constructor(node: BTreeNode, blackboard?: any) { + constructor(node: BTreeNode, blackboard?: any) { countUnnamed += 1; this.title = node.constructor.name + '(btree_' + (countUnnamed) + ')'; this._root = node; @@ -34,12 +34,12 @@ export class BehaviorTree implements IControl { } /** 设置行为逻辑中的共享数据 */ - public setObject(blackboard: any) { + setObject(blackboard: any) { this._blackboard = blackboard; } /** 执行行为树逻辑 */ - public run() { + run() { if (this._started) { console.error(`行为树【${this.title}】未调用步骤,在最后一次调用步骤时有一个任务未完成`); } @@ -52,16 +52,16 @@ export class BehaviorTree implements IControl { node.run(this._blackboard); } - public running(node: BTreeNode) { + running(node: BTreeNode) { this._started = false; } - public success() { + success() { this._current.end(this._blackboard); this._started = false; } - public fail() { + fail() { this._current.end(this._blackboard); this._started = false; } diff --git a/assets/libs/behavior-tree/BranchNode.ts b/assets/libs/behavior-tree/BranchNode.ts index 8da3864..58c39bf 100644 --- a/assets/libs/behavior-tree/BranchNode.ts +++ b/assets/libs/behavior-tree/BranchNode.ts @@ -10,7 +10,7 @@ import { BTreeNode } from './BTreeNode'; /** 复合节点 */ export abstract class BranchNode extends BTreeNode { /** 子节点数组 */ - public children: Array; + children: Array; /** 当前任务索引 */ protected _actualTask!: number; /** 正在运行的节点 */ @@ -19,17 +19,17 @@ export abstract class BranchNode extends BTreeNode { /** 外部参数对象 */ protected _blackboard: any; - public constructor(nodes: Array) { + constructor(nodes: Array) { super(); this.children = nodes || []; } - public start() { + start() { this._actualTask = 0; super.start(); } - public run(blackboard?: any) { + run(blackboard?: any) { if (this.children.length == 0) { // 没有子任务直接视为执行失败 this._control.fail(); } @@ -53,17 +53,17 @@ export abstract class BranchNode extends BTreeNode { node.run(this._blackboard); } - public running(node: BTreeNode) { + running(node: BTreeNode) { this._nodeRunning = node; this._control.running(node); } - public success() { + success() { this._nodeRunning = null; this._runningNode.end(this._blackboard); } - public fail() { + fail() { this._nodeRunning = null; this._runningNode.end(this._blackboard); } diff --git a/assets/libs/behavior-tree/Decorator.ts b/assets/libs/behavior-tree/Decorator.ts index b903c91..4e80744 100644 --- a/assets/libs/behavior-tree/Decorator.ts +++ b/assets/libs/behavior-tree/Decorator.ts @@ -12,7 +12,7 @@ import { BTreeNode } from './BTreeNode'; * 如果装饰器是true 它所在的子树会被执行,如果是false 所在的子树不会被执行 */ export class Decorator extends BTreeNode { - public node!: BTreeNode; + node!: BTreeNode; constructor(node?: string | BTreeNode) { super() @@ -25,17 +25,17 @@ export class Decorator extends BTreeNode { this.node = BehaviorTree.getNode(node); } - public start() { + start() { this.node.setControl(this); this.node.start(); super.start(); } - public end() { + end() { this.node.end(); } - public run(blackboard: any) { + run(blackboard: any) { this.node.run(blackboard); } } diff --git a/assets/libs/behavior-tree/Selector.ts b/assets/libs/behavior-tree/Selector.ts index 836e4e8..b375609 100644 --- a/assets/libs/behavior-tree/Selector.ts +++ b/assets/libs/behavior-tree/Selector.ts @@ -11,12 +11,12 @@ import { BranchNode } from './BranchNode'; * 只要子节点有一个返回true,则停止执行其它子节点,并且Selector返回true。如果所有子节点都返回false,则Selector返回false。 */ export class Selector extends BranchNode { - public success() { + success() { super.success() this._control.success(); } - public fail() { + fail() { super.fail() this._actualTask += 1; diff --git a/assets/libs/behavior-tree/Sequence.ts b/assets/libs/behavior-tree/Sequence.ts index f989bab..05f33d9 100644 --- a/assets/libs/behavior-tree/Sequence.ts +++ b/assets/libs/behavior-tree/Sequence.ts @@ -16,7 +16,7 @@ export class Sequence extends BranchNode { super(nodes); } - public success() { + success() { super.success(); this._actualTask += 1; @@ -28,7 +28,7 @@ export class Sequence extends BranchNode { } } - public fail() { + fail() { super.fail(); this._control.fail(); } -- Gitee From 37900d82191746cde9d29433d12b50407c014a2f Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 14:40:28 +0800 Subject: [PATCH 17/37] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=A0=BC=E5=BC=8F=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=88=86=E7=BB=84=E8=AE=BE=E7=BD=AE=E6=B8=B8=E6=88=8F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=8C=E6=96=B9=E4=BE=BF=E5=BC=80=E5=8F=91=E3=80=81?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E3=80=81=E7=94=9F=E4=BA=A7=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/Root.ts | 4 +- assets/module/config/BuildTimeConstants.ts | 2 +- assets/module/config/Config.ts | 3 +- assets/module/config/GameConfig.ts | 76 +++++++++++++--------- 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/assets/core/Root.ts b/assets/core/Root.ts index a0ae880..98e18cb 100644 --- a/assets/core/Root.ts +++ b/assets/core/Root.ts @@ -4,7 +4,7 @@ * @LastEditors: dgflash * @LastEditTime: 2023-08-28 10:02:57 */ -import { _decorator, Component, director, Game, game, JsonAsset, Node, resources, screen, sys } from "cc"; +import { _decorator, Component, director, Game, game, JsonAsset, Node, profiler, resources, screen, sys } from "cc"; import { GameConfig } from "../module/config/GameConfig"; import { GameQueryConfig } from "../module/config/GameQueryConfig"; import { oops, version } from "./Oops"; @@ -94,6 +94,8 @@ export class Root extends Component { //@ts-ignore oops.gui.initLayer(this.gui, config.json.gui); + // 初始化统计信息 + oops.config.game.stats ? profiler.showStats() : profiler.hideStats(); // 初始化每秒传输帧数 game.frameRate = oops.config.game.frameRate; diff --git a/assets/module/config/BuildTimeConstants.ts b/assets/module/config/BuildTimeConstants.ts index 89cfa74..81fc32a 100644 --- a/assets/module/config/BuildTimeConstants.ts +++ b/assets/module/config/BuildTimeConstants.ts @@ -10,7 +10,7 @@ const keys = (Object.keys(buildTimeConstants) as (keyof typeof buildTimeConstant /* 游戏运行环境 */ export class BuildTimeConstants { - constructor() { + toString() { const keyNameMaxLen = keys.reduce((len, key) => Math.max(len, key.length), 0); const enviroment = `${keys.map((key) => { const value = buildTimeConstants[key]; diff --git a/assets/module/config/Config.ts b/assets/module/config/Config.ts index e3fece8..1a1b830 100644 --- a/assets/module/config/Config.ts +++ b/assets/module/config/Config.ts @@ -5,13 +5,14 @@ * @LastEditTime: 2022-11-01 15:47:16 */ +import { BuildTimeConstants } from "./BuildTimeConstants"; import { GameConfig } from "./GameConfig"; import { GameQueryConfig } from "./GameQueryConfig"; /** 游戏配置静态访问类 */ export class Config { /** 环境常量 */ - // btc!: BuildTimeConstants; + btc: BuildTimeConstants = new BuildTimeConstants(); /** 游戏配置数据,版本号、支持语种等数据 */ game!: GameConfig; diff --git a/assets/module/config/GameConfig.ts b/assets/module/config/GameConfig.ts index 06e7eca..2f0ac6c 100644 --- a/assets/module/config/GameConfig.ts +++ b/assets/module/config/GameConfig.ts @@ -20,27 +20,55 @@ export enum GameConfigCustomType { export class GameConfig { /** 客户端版本号配置 */ get version(): string { - return this._data.config.version; - } - /** 游戏每秒传输帧数 */ - get frameRate(): number { - return this._data.config.frameRate; + return this.data.version; } /** 本地存储内容加密 key */ get localDataKey(): string { - return this._data.config.localDataKey; + return this.data.localDataKey; } /** 本地存储内容加密 iv */ get localDataIv(): string { - return this._data.config.localDataIv; + return this.data.localDataIv; + } + /** 游戏每秒传输帧数 */ + get frameRate(): number { + return this.data.frameRate; + } + /** 是否开启移动设备安全区域适配 */ + get mobileSafeArea(): boolean { + return this.data.mobileSafeArea || false; + } + /** 加载界面资源超时提示 */ + get loadingTimeoutGui(): number { + return this.data.loadingTimeoutGui || 1000; + } + /** 是否显示统计信息 */ + get stats(): number { + return this.data.stats; } /** Http 服务器地址 */ get httpServer(): string { - return this._data.config.httpServer; + return this.data.httpServer; } /** Http 请求超时时间 */ get httpTimeout(): number { - return this._data.config.httpTimeout; + return this.data.httpTimeout; + } + /** WebSocket 服务器地址 */ + get webSocketServer(): string { + return this.data.webSocketServer; + } + /** WebSocket 心跳间隔时间(毫秒) */ + get webSocketHeartTime(): number { + return this.data.webSocketHeartTime; + } + /** WebSocket 指定时间没收到消息就断开连接(毫秒) */ + get webSocketReceiveTime(): number { + return this.data.webSocketReceiveTime; + } + /** WebSocket 重连间隔时间(毫秒) */ + get webSocketReconnetTimeOut(): number { + return this.data.webSocketReconnetTimeOut; } /** 获取当前客户端支持的语言类型 */ @@ -65,40 +93,26 @@ export class GameConfig { return this._data.bundle.default; } - /** 加载界面资源超时提示 */ - get loadingTimeoutGui(): number { - return this._data.config.loadingTimeoutGui || 1000; - } - - /** 是否开启移动设备安全区域适配 */ - get mobileSafeArea(): boolean { - return this._data.config.mobileSafeArea || false; - } - private _data: any = null; /** 游戏配置数据 */ get data(): any { - return this._data; + return this._data.config[this._configType]; } + /** 当前游戏配置分组类型 */ + private _configType: GameConfigCustomType = GameConfigCustomType.Prod; + constructor(config: any) { this._data = Object.freeze(config.json); - + this.setConfigType(this._data.type); oops.log.logConfig(this._data, "游戏配置"); } - private _customType: GameConfigCustomType = GameConfigCustomType.Dev; - /** - * 设置自定义游戏参数配置类型 + * 设置游戏参数类型 * @param type */ - setCustomType(type: GameConfigCustomType) { - this._customType = type; - } - - /** 获取游戏自定义配置 */ - get custom(): any { - return this.data.custom[this._customType]; + setConfigType(type: GameConfigCustomType) { + this._configType = type; } } \ No newline at end of file -- Gitee From bb29cbf94e2bd2a32a52cb87c03860a5b023df32 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 16:19:43 +0800 Subject: [PATCH 18/37] =?UTF-8?q?Json=E9=85=8D=E7=BD=AE=E8=A1=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E6=94=AF=E6=8C=81zip=E6=A0=BC=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E9=AB=98=E5=A4=9A=E9=85=8D=E7=BD=AE=E8=A1=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E9=80=9F=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/loader/ZipLoader.ts | 87 ++++++++++++++++++ assets/core/common/loader/ZipLoader.ts.meta | 9 ++ assets/core/utils/JsonUtil.ts | 97 ++++++++++----------- assets/libs/gui/language/LanguagePack.ts | 2 +- assets/module/common/CCComp.ts | 4 +- assets/module/common/CCEntity.ts | 2 +- assets/module/common/CCVMParentComp.ts | 4 +- 7 files changed, 149 insertions(+), 56 deletions(-) create mode 100644 assets/core/common/loader/ZipLoader.ts create mode 100644 assets/core/common/loader/ZipLoader.ts.meta diff --git a/assets/core/common/loader/ZipLoader.ts b/assets/core/common/loader/ZipLoader.ts new file mode 100644 index 0000000..219d283 --- /dev/null +++ b/assets/core/common/loader/ZipLoader.ts @@ -0,0 +1,87 @@ +import { BufferAsset, SpriteFrame, Texture2D } from "cc"; +import { oops } from "db://oops-framework/core/Oops"; + +/** + * 加载Zip资源 + * 注: + * 1. 使用此功能需要教程项目中项目资源目录libs/jszip目录拷贝到自己的项目中 + * 2. 选中libs/jszip/jszip文件,属性检查器中勾选导入为插件、允许指点平台加载此库 + * 3. 压缩软件打包的 game.zip 修改为 game.bin 则可在游戏中加载 + */ +export class ZipLoader { + private static zips: Map = new Map(); + + /** + * 加载ZIP资源包 + * @param url + * @returns + */ + static load(url: string): Promise { + return new Promise((resolve, reject) => { + oops.res.load(url, BufferAsset, async (error: Error | null, asset: BufferAsset) => { + if (error) return reject(error); + + var zip = await JSZip.loadAsync(asset.buffer()); + this.zips.set(url, zip); + resolve(zip); + }) + }); + } + + static getJson(zipName: string, path: string): Promise { + return new Promise(async (resolve, reject) => { + var zip = this.zips.get(zipName); + if (zip == null) { + console.error(`名为【${zipName}】的资源包不存在`); + resolve(null); + return; + } + + var file = zip.file(path); + var json = JSON.parse(await file.async("text")); + resolve(json); + }); + } + + static getSpriteFrame(zipName: string, path: string): Promise { + return new Promise(async (resolve, reject) => { + var zip = this.zips.get(zipName); + if (zip == null) { + console.error(`名为【${zipName}】的资源包不存在`); + resolve(null!); + return; + } + + var file = zip.file(path); + var buf = await file.async("base64"); + var img = new Image(); + img.src = 'data:image/png;base64,' + buf; + img.onload = () => { + var texture = new Texture2D(); + texture.reset({ + width: img.width, + height: img.height + }); + texture.uploadData(img, 0, 0); + texture.loaded = true; + + var sf = new SpriteFrame(); + sf.texture = texture; + + resolve(sf); + } + }); + } + + /** 释放Zip资源 */ + static release(url?: string) { + if (url) { + oops.res.release(url); + } + else { + this.zips.forEach((value: JSZip, key: string) => { + oops.res.release(key); + }); + } + } +} \ No newline at end of file diff --git a/assets/core/common/loader/ZipLoader.ts.meta b/assets/core/common/loader/ZipLoader.ts.meta new file mode 100644 index 0000000..0b36f42 --- /dev/null +++ b/assets/core/common/loader/ZipLoader.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "2c6ce5e4-08fd-4ff1-b0b6-8c07d7192263", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 03778f9..7671f5f 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -6,100 +6,97 @@ */ import { JsonAsset } from "cc"; +import { ZipLoader } from "db://oops-framework/core/common/loader/ZipLoader"; import { resLoader } from "../common/loader/ResLoader"; /** 资源路径 */ -const path: string = "config/game/"; +const pathJson: string = "config/game/"; +/** 压缩包资源路径 */ +const pathZip: string = "config/game/game"; /** 数据缓存 */ const data: Map = new Map(); /** JSON数据表工具 */ export class JsonUtil { + /** 是否使用压缩包加载配置表 */ + static zip: boolean = false; + /** * 通知资源名从缓存中获取一个Json数据表 * @param name 资源名 */ static get(name: string): any { - if (data.has(name)) - return data.get(name); + if (data.has(name)) return data.get(name); } /** - * 通知资源名加载Json数据表 - * @param name 资源名 - * @param callback 资源加载完成回调 + * 异步加载Json数据表 + * @param name 资源名 */ - static load(name: string, callback: Function): void { - if (data.has(name)) - callback(data.get(name)); - else { - const url = path + name; - resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => { - if (err) { - console.warn(err.message); - callback(null); + static load(name: string): Promise { + return new Promise(async (resolve, reject) => { + let content: any = null; + if (data.has(name)) { + resolve(data.get(name)); + } + else { + const url = pathJson + name; + if (this.zip) { + content = await ZipLoader.getJson(pathZip, `${name}.json`); } else { + content = await resLoader.loadAsync(url, JsonAsset); + } + + if (content) { data.set(name, content.json); resLoader.release(url); - callback(content.json); + resolve(content.json); } - }); - } + } + }); } /** - * 异步加载Json数据表 - * @param name 资源名 + * 加载所有配置表数据到缓存中 + * @param isZip 是否为压缩包 + * @param zipNames 压缩包内的资源名列表 */ - static loadAsync(name: string): Promise { - return new Promise((resolve, reject) => { - if (data.has(name)) { - resolve(data.get(name)) + static loadDir(zipNames?: string[]): Promise { + return new Promise(async (resolve, reject) => { + if (this.zip && zipNames) { + await ZipLoader.load(pathZip); + zipNames.forEach(name => { + data.set(name, ZipLoader.getJson(pathZip, `${name}.json`)); + }); + resolve(); } else { - const url = path + name; - resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => { + resLoader.loadDir(pathJson, (err: Error | null, assets: JsonAsset[]) => { if (err) { - console.warn(err.message); - resolve(null); + console.error(err.message); + resolve(); } else { - data.set(name, content.json); - resLoader.release(url); - resolve(content.json); + assets.forEach(asset => { + data.set(asset.name, asset.json); + }); + resLoader.releaseDir(pathJson); + resolve(); } }); } }); } - /** 加载所有配置表数据到缓存中 */ - static loadDirAsync(): Promise { - return new Promise((resolve, reject) => { - resLoader.loadDir(path, (err: Error | null, assets: JsonAsset[]) => { - if (err) { - console.warn(err.message); - resolve(false); - } - else { - assets.forEach(asset => { - data.set(asset.name, asset.json); - }); - resLoader.releaseDir(path); - resolve(true); - } - }); - }); - } - /** * 通过指定资源名释放资源内存 * @param name 资源名 */ static release(name: string) { data.delete(name); + if (this.zip) ZipLoader.release(pathZip); } /** 清理所有数据 */ diff --git a/assets/libs/gui/language/LanguagePack.ts b/assets/libs/gui/language/LanguagePack.ts index 53bfadf..1d22726 100644 --- a/assets/libs/gui/language/LanguagePack.ts +++ b/assets/libs/gui/language/LanguagePack.ts @@ -44,7 +44,7 @@ export class LanguagePack { /** 多语言Excel配置表数据 */ private loadTable(lang: string): Promise { return new Promise(async (resolve, reject) => { - let json = await JsonUtil.loadAsync("Language"); + let json = await JsonUtil.load("Language"); if (json) { LanguageData.language.set(LanguageDataType.Excel, json); Logger.instance.logConfig("config/game/Language", "下载语言包 table 资源"); diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCComp.ts index afdcf77..f37a178 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCComp.ts @@ -38,13 +38,13 @@ export abstract class CCComp extends GameComponent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: ecs.Entity; + ent!: CCEntity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; - if (this.ent && this.ent instanceof CCEntity) { + if (this.ent) { this.ent.removeUi(cct); } else { diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index c0299e8..34ee2f9 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -21,7 +21,7 @@ export class CCEntity extends ecs.Entity { addChildSingleton(cls: any): T { if (this.singletons == null) this.singletons = new Map(); - let entity = cls.create() + let entity = cls.create(); this.singletons.set(cls, entity); this.addChild(entity); return entity as T; diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCVMParentComp.ts index 7a43c7d..9f6cbf4 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCVMParentComp.ts @@ -50,13 +50,13 @@ export abstract class CCVMParentComp extends VMParent implements ecs.IComp { static compName: string; canRecycle!: boolean; - ent!: ecs.Entity; + ent!: CCEntity; tid: number = -1; /** 从父节点移除自己 */ remove() { const cct = ECSModel.compCtors[this.tid]; - if (this.ent && this.ent instanceof CCEntity) { + if (this.ent) { this.ent.removeUi(cct); } else { -- Gitee From 0f8301108fcb2796645a680b96e2bd037e1da650 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 16:23:31 +0800 Subject: [PATCH 19/37] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/libs/gui/language/Language.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/libs/gui/language/Language.ts b/assets/libs/gui/language/Language.ts index 020efea..88fea18 100644 --- a/assets/libs/gui/language/Language.ts +++ b/assets/libs/gui/language/Language.ts @@ -53,7 +53,7 @@ export class LanguageManager { * @param language 语言名 * @param callback 多语言资源数据加载完成回调 */ - setLanguage(language: string, callback?: (success: boolean) => void) { + setLanguage(language: string, callback?: Function) { if (language == null || language == "") { language = this._defaultLanguage; } @@ -68,7 +68,7 @@ export class LanguageManager { } if (language === LanguageData.current) { - callback && callback(false); + callback && callback(); return; } @@ -78,7 +78,7 @@ export class LanguageManager { LanguageData.current = language; this._languagePack.updateLanguage(language); this._languagePack.releaseLanguageAssets(oldLanguage); - callback && callback(true); + callback && callback(); }); } -- Gitee From b21354e5d07fc962bbdfa97f9b40fe0343c7a5f0 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 16:54:02 +0800 Subject: [PATCH 20/37] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/loader/ZipLoader.ts | 8 ++++---- assets/core/utils/JsonUtil.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/core/common/loader/ZipLoader.ts b/assets/core/common/loader/ZipLoader.ts index 219d283..b13f3a6 100644 --- a/assets/core/common/loader/ZipLoader.ts +++ b/assets/core/common/loader/ZipLoader.ts @@ -1,5 +1,5 @@ import { BufferAsset, SpriteFrame, Texture2D } from "cc"; -import { oops } from "db://oops-framework/core/Oops"; +import { resLoader } from "./ResLoader"; /** * 加载Zip资源 @@ -18,7 +18,7 @@ export class ZipLoader { */ static load(url: string): Promise { return new Promise((resolve, reject) => { - oops.res.load(url, BufferAsset, async (error: Error | null, asset: BufferAsset) => { + resLoader.load(url, BufferAsset, async (error: Error | null, asset: BufferAsset) => { if (error) return reject(error); var zip = await JSZip.loadAsync(asset.buffer()); @@ -76,11 +76,11 @@ export class ZipLoader { /** 释放Zip资源 */ static release(url?: string) { if (url) { - oops.res.release(url); + resLoader.release(url); } else { this.zips.forEach((value: JSZip, key: string) => { - oops.res.release(key); + resLoader.release(key); }); } } diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 7671f5f..40d38e1 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -20,7 +20,7 @@ const data: Map = new Map(); /** JSON数据表工具 */ export class JsonUtil { /** 是否使用压缩包加载配置表 */ - static zip: boolean = false; + static zip: boolean = true; /** * 通知资源名从缓存中获取一个Json数据表 -- Gitee From 6d46a6b67e0a5e6c9b7005c9a593e255799bed15 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 17:12:36 +0800 Subject: [PATCH 21/37] . --- assets/core/utils/JsonUtil.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 40d38e1..7671f5f 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -20,7 +20,7 @@ const data: Map = new Map(); /** JSON数据表工具 */ export class JsonUtil { /** 是否使用压缩包加载配置表 */ - static zip: boolean = true; + static zip: boolean = false; /** * 通知资源名从缓存中获取一个Json数据表 -- Gitee From a864b3395e1138ad02c2d2a9a00a6a934af134a9 Mon Sep 17 00:00:00 2001 From: dgflash Date: Mon, 15 Sep 2025 21:41:46 +0800 Subject: [PATCH 22/37] =?UTF-8?q?Zip=E6=A0=BC=E5=BC=8F=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E8=A1=A8=EF=BC=8C=E5=8A=A0=E8=BD=BD=E5=AE=8C=E7=BC=93=E5=AD=98?= =?UTF-8?q?Json=E6=95=B0=E6=8D=AE=E5=90=8E=E8=87=AA=E5=8A=A8=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E8=B5=84=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/log/Logger.ts | 2 +- assets/core/utils/JsonUtil.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/core/common/log/Logger.ts b/assets/core/common/log/Logger.ts index 327e291..189bf1a 100644 --- a/assets/core/common/log/Logger.ts +++ b/assets/core/common/log/Logger.ts @@ -126,7 +126,7 @@ oops.log.table(object); * 打印标准日志 * @param msg 日志消息 */ - trace(msg: any, color: string = "#000000") { + trace(msg: any, color: string = "#FFFFFF") { this.print(LogType.Trace, msg, color); } diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 7671f5f..33d7ece 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -70,6 +70,7 @@ export class JsonUtil { zipNames.forEach(name => { data.set(name, ZipLoader.getJson(pathZip, `${name}.json`)); }); + ZipLoader.release(pathZip); resolve(); } else { @@ -96,7 +97,6 @@ export class JsonUtil { */ static release(name: string) { data.delete(name); - if (this.zip) ZipLoader.release(pathZip); } /** 清理所有数据 */ -- Gitee From bac2c0c710f6ceaa163ff834aa8f5eb93e07c458 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 16 Sep 2025 10:58:58 +0800 Subject: [PATCH 23/37] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/utils/DeviceUtil.ts | 3 --- assets/core/utils/TimeUtils.ts | 6 +++--- assets/libs/extension/DateExt.ts | 31 +++++++++++++++++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/assets/core/utils/DeviceUtil.ts b/assets/core/utils/DeviceUtil.ts index 823b687..02d4826 100644 --- a/assets/core/utils/DeviceUtil.ts +++ b/assets/core/utils/DeviceUtil.ts @@ -40,9 +40,6 @@ export class DeviceUtil { /** 是否为字节小游戏 */ static get isByteDance() { return sys.platform === sys.Platform.BYTEDANCE_MINI_GAME; } - /** 是否为百度小游戏 */ - static get isBaidu() { return sys.platform === sys.Platform.BAIDU_MINI_GAME; } - /** 是否为 vivo 小游戏 */ static get isVivo() { return sys.platform === sys.Platform.VIVO_MINI_GAME; } diff --git a/assets/core/utils/TimeUtils.ts b/assets/core/utils/TimeUtils.ts index 11a2873..dfd2161 100644 --- a/assets/core/utils/TimeUtils.ts +++ b/assets/core/utils/TimeUtils.ts @@ -6,7 +6,7 @@ export class TimeUtil { * @param time2 结束时间 * @returns */ - public static daysBetween(time1: number | string | Date, time2: number | string | Date): number { + static daysBetween(time1: number | string | Date, time2: number | string | Date): number { if (time2 == undefined) { time2 = +new Date(); } @@ -18,7 +18,7 @@ export class TimeUtil { } /** 间隔秒数,时间顺序无要求,最后会获取绝对值 */ - public static secsBetween(time1: number, time2: number) { + static secsBetween(time1: number, time2: number) { let dates = Math.abs((time2 - time1)) / (1000); dates = Math.floor(dates) + 1; return dates; @@ -28,7 +28,7 @@ export class TimeUtil { * 代码休眠时间 * @param ms 毫秒 */ - public static async sleep(ms: number) { + static async sleep(ms: number) { return new Promise((resolve) => { setTimeout(() => { resolve(); diff --git a/assets/libs/extension/DateExt.ts b/assets/libs/extension/DateExt.ts index 4120fec..46d72a2 100644 --- a/assets/libs/extension/DateExt.ts +++ b/assets/libs/extension/DateExt.ts @@ -1,10 +1,14 @@ declare global { interface Date { + /** 时间格式化 */ format(format: string): string; + /** 时间加法 */ + addTime(addMillis: number): Date; + /** 验证时间是否在指定范围 */ + range(t1: number | Date, t2: number | Date): boolean; } } -/** 格式化时间字符串 */ Date.prototype.format = function (format: string): string { const year: number = this.getFullYear(); const month: number = this.getMonth() + 1; @@ -35,4 +39,27 @@ Date.prototype.format = function (format: string): string { return r; }; -export { }; +Date.prototype.addTime = function (addMillis: number) { + return new Date(this.getTime() + addMillis); +} + +Date.prototype.range = function (d1: number | Date, d2: number | Date) { + let t1: number = -1; + let t2: number = -1; + if (d1 instanceof Date) + t1 = d1.getTime(); + else + t1 = d1; + if (d2 instanceof Date) + t2 = d2.getTime(); + else + t2 = d2; + + let now = this.getTime(); + if (now >= t1 && now < t2) { + return true; + } + return false; +} + +export { }; \ No newline at end of file -- Gitee From 4dbf10bb774310dfa6eae7d5c3e31190cac13170 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 16 Sep 2025 11:57:02 +0800 Subject: [PATCH 24/37] =?UTF-8?q?TimerManager=E5=AE=9A=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=B7=BB=E5=8A=A0=E5=A4=9A=E4=B8=AA=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/timer/TimerManager.ts | 79 +++++++++++++++++------- assets/libs/extension/DateExt.ts | 22 +++++-- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/assets/core/common/timer/TimerManager.ts b/assets/core/common/timer/TimerManager.ts index 8db5771..9700bf3 100644 --- a/assets/core/common/timer/TimerManager.ts +++ b/assets/core/common/timer/TimerManager.ts @@ -8,10 +8,29 @@ import { Component, game } from "cc"; import { StringUtil } from "../../utils/StringUtil"; import { Timer } from "./Timer"; +interface ITimer { + /** 倒计时编号 */ + id: string; + /** 定时器 */ + timer: Timer; + /** 数据对象 */ + object: any; + /** 修改数据对象的字段 */ + field: string; + /** 事件侦听器的目标和被叫方 */ + target: any; + /** 开始时间 */ + startTime: number; + /** 每秒触发事件 */ + onSeconds: Function[]; + /** 时间完成事件 */ + onCompletes: Function[]; +} + /** 时间管理 */ export class TimerManager extends Component { /** 倒计时数据 */ - private times: any = {}; + private times: { [key: string]: ITimer } = {}; /** 服务器时间 */ private date_s: Date = new Date(); /** 服务器初始时间 */ @@ -25,7 +44,7 @@ export class TimerManager extends Component { protected update(dt: number) { for (let key in this.times) { let data = this.times[key]; - let timer = data.timer as Timer; + let timer = data.timer; if (timer.update(dt)) { if (data.object[data.field] > 0) { data.object[data.field]--; @@ -35,8 +54,8 @@ export class TimerManager extends Component { this.onTimerComplete(data); } // 触发每秒回调事件 - else if (data.onSecond) { - data.onSecond.call(data.object); + else if (data.onSeconds) { + data.onSeconds.forEach(fn => fn.call(data.object)); } } } @@ -44,10 +63,8 @@ export class TimerManager extends Component { } /** 触发倒计时完成事件 */ - private onTimerComplete(data: any) { - if (data.onComplete) data.onComplete.call(data.target, data.object); - if (data.event) this.node.dispatchEvent(data.event); - + private onTimerComplete(data: ITimer) { + if (data.onCompletes) data.onCompletes.forEach(fn => fn.call(data.target, data.object)); delete this.times[data.id]; } @@ -58,7 +75,7 @@ export class TimerManager extends Component { * @param target 触发事件的对象 * @param onSecond 每秒事件 * @param onComplete 倒计时完成事件 - * @returns + * @returns 倒计时编号 * @example export class Test extends Component { private timeId!: string; @@ -81,18 +98,37 @@ export class TimerManager extends Component { const timer = new Timer(); timer.step = 1; - let data: any = {}; - data.id = StringUtil.guid(); - data.timer = timer; - data.object = object; // 管理对象 - data.field = field; // 时间字段 - data.onSecond = onSecond; // 每秒事件 - data.onComplete = onComplete; // 倒计时完成事件 - data.target = target + let data: ITimer = { + id: StringUtil.guid(), + timer: timer, + object: object, + field: field, + onSeconds: [], + onCompletes: [], + target: target, + startTime: this.getTime() + }; + if (onSecond) data.onSeconds.push(onSecond); + if (onComplete) data.onCompletes.push(onComplete); + this.times[data.id] = data; return data.id; } + /** + * 为指定倒计时添加回调事件 + * @param id 倒计时编号 + * @param onSecond 每秒事件 + * @param onComplete 倒计时完成事件 + */ + addCallback(id: string, onSecond: Function, onComplete: Function) { + let data = this.times[id]; + if (data) { + if (onSecond) data.onSeconds.push(onSecond); + if (onComplete) data.onCompletes.push(onComplete); + } + } + /** * 在指定对象上注销一个倒计时的回调管理器 * @param id 时间对象唯一表示 @@ -153,23 +189,24 @@ export class TimerManager extends Component { /** 游戏最小化时记录时间数据 */ save(): void { for (let key in this.times) { - this.times[key].startTime = this.getTime(); + let data: ITimer = this.times[key]; + data.startTime = this.getTime(); } } /** 游戏最大化时回复时间数据 */ load(): void { for (let key in this.times) { - let interval = Math.floor((this.getTime() - (this.times[key].startTime || this.getTime())) / 1000); let data = this.times[key]; + let interval = Math.floor((this.getTime() - (data.startTime || this.getTime())) / 1000); data.object[data.field] = data.object[data.field] - interval; if (data.object[data.field] <= 0) { data.object[data.field] = 0; this.onTimerComplete(data); } else { - this.times[key].startTime = null; + data.object[data.field] = 0; } } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/assets/libs/extension/DateExt.ts b/assets/libs/extension/DateExt.ts index 46d72a2..36a44a5 100644 --- a/assets/libs/extension/DateExt.ts +++ b/assets/libs/extension/DateExt.ts @@ -1,10 +1,22 @@ declare global { interface Date { - /** 时间格式化 */ + /** + * 时间格式化 + * @param format 时间格式,例如:yy-mm-dd hh:mm:ss + */ format(format: string): string; - /** 时间加法 */ + + /** + * 时间加法 + * @param addMillis 时间加法,单位毫秒 + */ addTime(addMillis: number): Date; - /** 验证时间是否在指定范围 */ + + /** + * 验证时间是否在指定范围 + * @param t1 范围开始时间 + * @param t2 范围结束时间 + */ range(t1: number | Date, t2: number | Date): boolean; } } @@ -39,11 +51,11 @@ Date.prototype.format = function (format: string): string { return r; }; -Date.prototype.addTime = function (addMillis: number) { +Date.prototype.addTime = function (addMillis: number): Date { return new Date(this.getTime() + addMillis); } -Date.prototype.range = function (d1: number | Date, d2: number | Date) { +Date.prototype.range = function (d1: number | Date, d2: number | Date): boolean { let t1: number = -1; let t2: number = -1; if (d1 instanceof Date) -- Gitee From 9b6a18a110c7e274362000eb1855e5704ec206e0 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 16 Sep 2025 15:32:01 +0800 Subject: [PATCH 25/37] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCEntity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index 34ee2f9..c605027 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -13,7 +13,7 @@ import { CCVMParentComp } from "./CCVMParentComp"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; /** ECS 游戏模块实体 */ -export class CCEntity extends ecs.Entity { +export abstract class CCEntity extends ecs.Entity { /** 单例子实体 */ private singletons: Map = null!; -- Gitee From e0cfcb60715cd17745e775ecba10adf2bfac4b5e Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 16 Sep 2025 15:46:23 +0800 Subject: [PATCH 26/37] . --- assets/core/common/log/Logger.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/core/common/log/Logger.ts b/assets/core/common/log/Logger.ts index 189bf1a..a12dd34 100644 --- a/assets/core/common/log/Logger.ts +++ b/assets/core/common/log/Logger.ts @@ -126,7 +126,7 @@ oops.log.table(object); * 打印标准日志 * @param msg 日志消息 */ - trace(msg: any, color: string = "#FFFFFF") { + trace(msg: any, color: string = "#000000ff") { this.print(LogType.Trace, msg, color); } -- Gitee From d2c47ff78448b3e23a43bfd296af31d40e88c21c Mon Sep 17 00:00:00 2001 From: dgflash Date: Wed, 17 Sep 2025 13:45:46 +0800 Subject: [PATCH 27/37] =?UTF-8?q?=E4=BF=AE=E5=A4=8DLabelTime=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E4=BB=8E1=E5=A4=A9=E5=87=8F=E5=88=B0=E5=B0=8F?= =?UTF-8?q?=E4=BA=8E1=E5=A4=A9=E6=97=B6=EF=BC=8C=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/libs/gui/label/LabelTime.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/assets/libs/gui/label/LabelTime.ts b/assets/libs/gui/label/LabelTime.ts index e370c7f..2639553 100644 --- a/assets/libs/gui/label/LabelTime.ts +++ b/assets/libs/gui/label/LabelTime.ts @@ -18,7 +18,7 @@ export default class LabelTime extends Label { @property({ tooltip: "天数数据格式化", }) - dayFormat: string = "{0} day"; + dayFormat: string = "{0}天{1}时"; @property({ tooltip: "时间格式化", @@ -26,7 +26,7 @@ export default class LabelTime extends Label { timeFormat: string = "{0}:{1}:{2}"; @property({ - tooltip: "是否有00", + tooltip: "时间是否有固定二位数据", }) zeroize: boolean = true; @@ -74,7 +74,7 @@ export default class LabelTime extends Label { let dataFormat = this.dayFormat; let index = dataFormat.indexOf("{1}"); if (hours == 0 && index > -1) { - dataFormat = dataFormat.substring(0, index - 1); + dataFormat = dataFormat.substring(0, index); } let df = dataFormat; if (date > 1 && dataFormat.indexOf("days") < 0) { @@ -83,7 +83,13 @@ export default class LabelTime extends Label { if (date < 2) { df = df.replace("days", "day"); } - this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..." + + if (this.zeroize) { + this.result = this.replace(df, date, this.coverString(hours)); + } + else { + this.result = this.replace(df, date, hours); // 如果天大于1,则显示 "1 Day..." + } } else { hours += date * 24; @@ -214,4 +220,4 @@ export default class LabelTime extends Label { timing_end() { this.unscheduleAllCallbacks(); } -} +} \ No newline at end of file -- Gitee From 804f18cd8c58d91ce157eab22ab72c5742763519 Mon Sep 17 00:00:00 2001 From: dgflash Date: Wed, 17 Sep 2025 16:22:52 +0800 Subject: [PATCH 28/37] =?UTF-8?q?StringFormat.kmbt=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E4=B8=8E=E5=A4=9A=E8=AF=AD=E8=A8=80=E7=B1=BB=E5=9E=8B=E5=85=B3?= =?UTF-8?q?=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/libs/gui/label/LabelTime.ts | 2 +- assets/libs/model-view/StringFormat.ts | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/assets/libs/gui/label/LabelTime.ts b/assets/libs/gui/label/LabelTime.ts index 2639553..d8b9b07 100644 --- a/assets/libs/gui/label/LabelTime.ts +++ b/assets/libs/gui/label/LabelTime.ts @@ -18,7 +18,7 @@ export default class LabelTime extends Label { @property({ tooltip: "天数数据格式化", }) - dayFormat: string = "{0}天{1}时"; + dayFormat: string = "{0}天{1}小时"; @property({ tooltip: "时间格式化", diff --git a/assets/libs/model-view/StringFormat.ts b/assets/libs/model-view/StringFormat.ts index 89e3b52..24b8d8e 100644 --- a/assets/libs/model-view/StringFormat.ts +++ b/assets/libs/model-view/StringFormat.ts @@ -1,3 +1,5 @@ +import { LanguageData } from "../gui/language/LanguageData"; + /** * 数值格式化函数, 通过语义解析自动设置值的范围 * //整数 @@ -93,19 +95,20 @@ class StringFormat { } /** 将数字缩短显示为KMBT单位 大写,目前只支持英文 */ - private kmbt(value: number, lang: string = 'en') { + private kmbt(value: number) { //10^4=万, 10^8=亿,10^12=兆,10^16=京, - let counts = [1000, 1000000, 1000000000, 1000000000000]; - let units = ['', 'K', 'M', 'B', 'T']; + let counts: number[] = null!; + let units: string[] = null!; - switch (lang) { + switch (LanguageData.current) { case 'zh': //10^4=万, 10^8=亿,10^12=兆,10^16=京, counts = [10000, 100000000, 1000000000000, 10000000000000000]; units = ['', '万', '亿', '兆', '京']; break; - default: + counts = [1000, 1000000, 1000000000, 1000000000000]; + units = ['', 'K', 'M', 'B', 'T']; break; } -- Gitee From c9c6a0bf25a99229a23e1cdcb279ee931e382697 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 18 Sep 2025 14:00:20 +0800 Subject: [PATCH 29/37] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0CCBusiness?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91=E5=A4=84=E7=90=86=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=202.=20CCComp=E6=94=B9=E5=90=8D=E4=B8=BACCView=203.?= =?UTF-8?q?=20CCVMParentComp=E6=94=B9=E5=90=8D=E4=B8=BACCViewVM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/event/EventMessage.ts | 10 +- assets/module/common/CCBusiness.ts | 85 +++++++++++ .../{CCComp.ts.meta => CCBusiness.ts.meta} | 2 +- assets/module/common/CCEntity.ts | 77 +++++++++- assets/module/common/{CCComp.ts => CCView.ts} | 110 +++++++------- ...{CCVMParentComp.ts.meta => CCView.ts.meta} | 2 +- .../common/{CCVMParentComp.ts => CCViewVM.ts} | 134 +++++++++--------- assets/module/common/CCViewVM.ts.meta | 9 ++ 8 files changed, 295 insertions(+), 134 deletions(-) create mode 100644 assets/module/common/CCBusiness.ts rename assets/module/common/{CCComp.ts.meta => CCBusiness.ts.meta} (70%) rename assets/module/common/{CCComp.ts => CCView.ts} (89%) rename assets/module/common/{CCVMParentComp.ts.meta => CCView.ts.meta} (70%) rename assets/module/common/{CCVMParentComp.ts => CCViewVM.ts} (89%) create mode 100644 assets/module/common/CCViewVM.ts.meta diff --git a/assets/core/common/event/EventMessage.ts b/assets/core/common/event/EventMessage.ts index 23f5380..0a77c91 100644 --- a/assets/core/common/event/EventMessage.ts +++ b/assets/core/common/event/EventMessage.ts @@ -15,13 +15,13 @@ export type ListenerFunc = (event: string, ...args: any) => void /** 框架内部全局事件 */ export enum EventMessage { /** 游戏从后台进入事件 */ - GAME_SHOW = "GAME_ENTER", + GAME_SHOW = "onGameShow", /** 游戏切到后台事件 */ - GAME_HIDE = "GAME_EXIT", + GAME_HIDE = "onGameHide", /** 游戏画笔尺寸变化事件 */ - GAME_RESIZE = "GAME_RESIZE", + GAME_RESIZE = "onGameResize", /** 游戏全屏事件 */ - GAME_FULL_SCREEN = "GAME_FULL_SCREEN", + GAME_FULL_SCREEN = "onGameFullScreen", /** 游戏旋转屏幕事件 */ - GAME_ORIENTATION = "GAME_ORIENTATION" + GAME_ORIENTATION = "onGameOrientation" } diff --git a/assets/module/common/CCBusiness.ts b/assets/module/common/CCBusiness.ts new file mode 100644 index 0000000..1af8c9c --- /dev/null +++ b/assets/module/common/CCBusiness.ts @@ -0,0 +1,85 @@ +/* + * @Author: dgflash + * @Date: 2025-09-18 10:20:51 + * @LastEditors: dgflash + * @LastEditTime: 2025-09-18 17:20:51 + */ + +import { EventDispatcher } from "../../core/common/event/EventDispatcher"; +import { ListenerFunc } from "../../core/common/event/EventMessage"; +import { CCEntity } from "./CCEntity"; + +/** 业务逻辑 */ +export class CCBusiness { + ent!: CCEntity; + + /** 业务逻辑初台化 */ + protected init() { + + } + + destroy() { + // 释放消息对象 + if (this._event) { + this._event.destroy(); + this._event = null; + } + } + + //#region 全局事件管理 + private _event: EventDispatcher | null = null; + /** 全局事件管理器 */ + private get event(): EventDispatcher { + if (this._event == null) this._event = new EventDispatcher(); + return this._event; + } + + /** + * 注册全局事件 + * @param event 事件名 + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的this对象 + */ + on(event: string, listener: ListenerFunc, object: any) { + this.event.on(event, listener, object); + } + + /** + * 移除全局事件 + * @param event 事件名 + */ + off(event: string) { + this.event.off(event); + } + + /** + * 触发全局事件 + * @param event 事件名 + * @param args 事件参数 + */ + dispatchEvent(event: string, ...args: any) { + this.event.dispatchEvent(event, ...args); + } + + /** + * 批量设置全局事件 + * @example + * this.setEvent("onGlobal"); + * this.dispatchEvent("onGlobal", "全局事件"); + * + * onGlobal(event: string, args: any) { console.log(args) }; + */ + protected setEvent(...args: string[]) { + const self: any = this; + for (const name of args) { + const func = self[name]; + if (func) + this.on(name, func, this); + else + console.error(`名为【${name}】的全局事方法不存在`); + } + } + + //#endregion + +} \ No newline at end of file diff --git a/assets/module/common/CCComp.ts.meta b/assets/module/common/CCBusiness.ts.meta similarity index 70% rename from assets/module/common/CCComp.ts.meta rename to assets/module/common/CCBusiness.ts.meta index 19c6741..fcbff47 100644 --- a/assets/module/common/CCComp.ts.meta +++ b/assets/module/common/CCBusiness.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "dd2077e2-c862-4b7f-9afe-6e488c83076d", + "uuid": "4a753a57-2867-478e-b770-c05d96535c4e", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index c605027..0efd3b8 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -7,20 +7,25 @@ import { ViewUtil } from "../../core/utils/ViewUtil"; import { ecs } from "../../libs/ecs/ECS"; import { ECSEntity } from "../../libs/ecs/ECSEntity"; import { CompType } from "../../libs/ecs/ECSModel"; -import { CCComp } from "./CCComp"; -import { CCVMParentComp } from "./CCVMParentComp"; +import { CCBusiness } from "./CCBusiness"; +import { CCView } from "./CCView"; +import { CCViewVM } from "./CCViewVM"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; /** ECS 游戏模块实体 */ export abstract class CCEntity extends ecs.Entity { + //#region 子模块管理 /** 单例子实体 */ private singletons: Map = null!; /** 添加单例子实体 */ addChildSingleton(cls: any): T { if (this.singletons == null) this.singletons = new Map(); - + if (this.singletons.has(cls)) { + console.error(`${cls.name} 单例子实体已存在`); + return null!; + } let entity = cls.create(); this.singletons.set(cls, entity); this.addChild(entity); @@ -40,7 +45,9 @@ export abstract class CCEntity extends ecs.Entity { this.removeChild(entity); } } + //#endregion + //#region 游戏视图层管理 /** * 通过资源内存中获取预制上的组件添加到ECS实体中 * @param ctor 界面逻辑组件 @@ -48,7 +55,7 @@ export abstract class CCEntity extends ecs.Entity { * @param path 显示资源地址 * @param bundleName 资源包名称 */ - addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { + addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { const node = ViewUtil.createPrefabNode(path, bundleName); const comp = node.getComponent(ctor)!; this.add(comp); @@ -61,7 +68,7 @@ export abstract class CCEntity extends ecs.Entity { * @param params 界面参数 * @returns 界面节点 */ - addUi(ctor: ECSCtor, params?: UIParam): Promise { + addUi(ctor: ECSCtor, params?: UIParam): Promise { return new Promise(async (resolve, reject) => { const key = gui.internal.getKey(ctor); if (key) { @@ -108,4 +115,64 @@ export abstract class CCEntity extends ecs.Entity { this.remove(ctor); } } + //#endregion + + //#region 游戏业务层管理 + /** 模块业务逻辑组件 */ + private businesss: Map = null!; + + /** + * 批量添加组件 + * @param ctors 组件类 + * @returns + */ + addBusinesss(...clss: any[]) { + for (let ctor of clss) { + this.addBusiness(ctor); + } + } + + /** + * 添加业务逻辑组件 + * @param cls 业务逻辑组件类 + * @returns 业务逻辑组件实例 + */ + addBusiness(cls: any): T { + if (this.businesss == null) this.businesss = new Map(); + if (this.businesss.has(cls)) { + console.error(`${cls.name} 业务逻辑组件已存在`); + return null!; + } + let business = new cls(); + business.ent = this; + business.init(); + this.businesss.set(cls, business); + return business as T; + } + + /** + * 获取业务逻辑组件 + * @param cls 业务逻辑组件类 + * @returns 业务逻辑组件实例 + */ + getBusiness(cls: any): T { + return this.businesss.get(cls) as T; + } + + /** + * 移除业务逻辑组件 + * @param cls 业务逻辑组件类 + */ + removeBusiness(cls: any) { + let business = this.businesss.get(cls); + if (business) this.businesss.delete(cls); + } + //#endregion + + destroy(): void { + this.singletons.clear(); + this.businesss.forEach(business => business.destroy()); + this.businesss.clear(); + super.destroy(); + } } \ No newline at end of file diff --git a/assets/module/common/CCComp.ts b/assets/module/common/CCView.ts similarity index 89% rename from assets/module/common/CCComp.ts rename to assets/module/common/CCView.ts index f37a178..7d93c31 100644 --- a/assets/module/common/CCComp.ts +++ b/assets/module/common/CCView.ts @@ -1,56 +1,56 @@ -/* - * @Author: dgflash - * @Date: 2021-11-11 19:05:32 - * @LastEditors: dgflash - * @LastEditTime: 2022-09-06 17:20:51 - */ - -import { ecs } from '../../libs/ecs/ECS'; -import { ECSModel } from '../../libs/ecs/ECSModel'; -import { CCEntity } from './CCEntity'; -import { GameComponent } from './GameComponent'; - -/** - * ECS 游戏显示对象组件 - * - * 功能介绍: - * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 - * 2. 对象自带全局事件监听、释放、发送全局消息功能 - * 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象 - * - * 应用场景 - * 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象 - * - * @example -@ccclass('RoleViewComp') -@ecs.register('RoleView', false) -export class RoleViewComp extends CCComp { - @property({ type: sp.Skeleton, tooltip: '角色动画' }) - spine: sp.Skeleton = null!; - - onLoad(){ - - } -} - */ -export abstract class CCComp extends GameComponent implements ecs.IComp { - static tid: number = -1; - static compName: string; - - canRecycle!: boolean; - ent!: CCEntity; - tid: number = -1; - - /** 从父节点移除自己 */ - remove() { - const cct = ECSModel.compCtors[this.tid]; - if (this.ent) { - this.ent.removeUi(cct); - } - else { - console.error(`组件 ${this.name} 移除失败,组件未注册`); - } - } - - abstract reset(): void; +/* + * @Author: dgflash + * @Date: 2021-11-11 19:05:32 + * @LastEditors: dgflash + * @LastEditTime: 2022-09-06 17:20:51 + */ + +import { ecs } from '../../libs/ecs/ECS'; +import { ECSModel } from '../../libs/ecs/ECSModel'; +import { CCEntity } from './CCEntity'; +import { GameComponent } from './GameComponent'; + +/** + * ECS 游戏显示对象组件 + * + * 功能介绍: + * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 + * 2. 对象自带全局事件监听、释放、发送全局消息功能 + * 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象 + * + * 应用场景 + * 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象 + * + * @example +@ccclass('RoleViewComp') +@ecs.register('RoleView', false) +export class RoleViewComp extends CCView { + @property({ type: sp.Skeleton, tooltip: '角色动画' }) + spine: sp.Skeleton = null!; + + onLoad(){ + + } +} + */ +export abstract class CCView extends GameComponent implements ecs.IComp { + static tid: number = -1; + static compName: string; + + canRecycle!: boolean; + ent!: CCEntity; + tid: number = -1; + + /** 从父节点移除自己 */ + remove() { + const cct = ECSModel.compCtors[this.tid]; + if (this.ent) { + this.ent.removeUi(cct); + } + else { + console.error(`组件 ${this.name} 移除失败,组件未注册`); + } + } + + abstract reset(): void; } \ No newline at end of file diff --git a/assets/module/common/CCVMParentComp.ts.meta b/assets/module/common/CCView.ts.meta similarity index 70% rename from assets/module/common/CCVMParentComp.ts.meta rename to assets/module/common/CCView.ts.meta index 922f5b2..d44693a 100644 --- a/assets/module/common/CCVMParentComp.ts.meta +++ b/assets/module/common/CCView.ts.meta @@ -2,7 +2,7 @@ "ver": "4.0.24", "importer": "typescript", "imported": true, - "uuid": "5908a4e6-3359-48b6-95e0-a3b44ea50790", + "uuid": "7f4397f9-04cd-42e3-a323-d468c93b19c0", "files": [], "subMetas": {}, "userData": {} diff --git a/assets/module/common/CCVMParentComp.ts b/assets/module/common/CCViewVM.ts similarity index 89% rename from assets/module/common/CCVMParentComp.ts rename to assets/module/common/CCViewVM.ts index 9f6cbf4..c394e14 100644 --- a/assets/module/common/CCVMParentComp.ts +++ b/assets/module/common/CCViewVM.ts @@ -1,68 +1,68 @@ -/* - * @Author: dgflash - * @Date: 2021-11-11 19:05:32 - * @LastEditors: dgflash - * @LastEditTime: 2022-09-06 17:22:05 - */ - -import { ecs } from '../../libs/ecs/ECS'; -import { ECSModel } from '../../libs/ecs/ECSModel'; -import VMParent from '../../libs/model-view/VMParent'; -import { CCEntity } from './CCEntity'; - -/** - * 支持 MVVM 功能的 ECS 游戏显示对象组件 - * - * 使用方法: - * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 - * 2. 对象自带全局事件监听、释放、发送全局消息功能 - * 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象(节点名不能有重名) - * 4. 对象支持 VMParent 所有功能 - * - * 应用场景 - * 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象 - * - * @example -@ccclass('LoadingViewComp') -@ecs.register('LoadingView', false) -export class LoadingViewComp extends CCVMParentComp { - // VM 组件绑定数据 - data: any = { - // 加载资源当前进度 - finished: 0, - // 加载资源最大进度 - total: 0, - // 加载资源进度比例值 - progress: "0", - // 加载流程中提示文本 - prompt: "" - }; - - private progress: number = 0; - - reset(): void { - - } -} - */ -export abstract class CCVMParentComp extends VMParent implements ecs.IComp { - static tid: number = -1; - static compName: string; - - canRecycle!: boolean; - ent!: CCEntity; - tid: number = -1; - - /** 从父节点移除自己 */ - remove() { - const cct = ECSModel.compCtors[this.tid]; - if (this.ent) { - this.ent.removeUi(cct); - } - else { - console.error(`组件 ${this.name} 移除失败,组件未注册`); - } - } - - abstract reset(): void; +/* + * @Author: dgflash + * @Date: 2021-11-11 19:05:32 + * @LastEditors: dgflash + * @LastEditTime: 2022-09-06 17:22:05 + */ + +import { ecs } from '../../libs/ecs/ECS'; +import { ECSModel } from '../../libs/ecs/ECSModel'; +import VMParent from '../../libs/model-view/VMParent'; +import { CCEntity } from './CCEntity'; + +/** + * 支持 MVVM 功能的 ECS 游戏显示对象组件 + * + * 使用方法: + * 1. 对象拥有 cc.Component 组件功能与 ecs.Comp 组件功能 + * 2. 对象自带全局事件监听、释放、发送全局消息功能 + * 3. 对象管理的所有节点摊平,直接通过节点名获取cc.Node对象(节点名不能有重名) + * 4. 对象支持 VMParent 所有功能 + * + * 应用场景 + * 1. 网络游戏,优先有数据对象,然后创建视图对象,当释放视图组件时,部分场景不希望释放数据对象 + * + * @example +@ccclass('LoadingViewComp') +@ecs.register('LoadingView', false) +export class LoadingViewComp extends CCViewVM { + // VM 组件绑定数据 + data: any = { + // 加载资源当前进度 + finished: 0, + // 加载资源最大进度 + total: 0, + // 加载资源进度比例值 + progress: "0", + // 加载流程中提示文本 + prompt: "" + }; + + private progress: number = 0; + + reset(): void { + + } +} + */ +export abstract class CCViewVM extends VMParent implements ecs.IComp { + static tid: number = -1; + static compName: string; + + canRecycle!: boolean; + ent!: CCEntity; + tid: number = -1; + + /** 从父节点移除自己 */ + remove() { + const cct = ECSModel.compCtors[this.tid]; + if (this.ent) { + this.ent.removeUi(cct); + } + else { + console.error(`组件 ${this.name} 移除失败,组件未注册`); + } + } + + abstract reset(): void; } \ No newline at end of file diff --git a/assets/module/common/CCViewVM.ts.meta b/assets/module/common/CCViewVM.ts.meta new file mode 100644 index 0000000..2536e00 --- /dev/null +++ b/assets/module/common/CCViewVM.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "33d31b2d-c771-4759-9fc6-96bbd5bcfa15", + "files": [], + "subMetas": {}, + "userData": {} +} -- Gitee From 6e688dcdd159c9bbabc5788083be786423b5dba8 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 18 Sep 2025 14:09:26 +0800 Subject: [PATCH 30/37] . --- assets/module/common/CCBusiness.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/module/common/CCBusiness.ts b/assets/module/common/CCBusiness.ts index 1af8c9c..be20d4a 100644 --- a/assets/module/common/CCBusiness.ts +++ b/assets/module/common/CCBusiness.ts @@ -27,6 +27,7 @@ export class CCBusiness { } //#region 全局事件管理 + private _event: EventDispatcher | null = null; /** 全局事件管理器 */ private get event(): EventDispatcher { @@ -81,5 +82,4 @@ export class CCBusiness { } //#endregion - } \ No newline at end of file -- Gitee From f32a453dd2539ed18a3f6e1469a80c106130b202 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 18 Sep 2025 16:17:09 +0800 Subject: [PATCH 31/37] =?UTF-8?q?=E4=BF=AE=E6=94=B9JsonUtil.load=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E9=85=8D=E7=BD=AE=E8=A1=A8=E6=97=B6=EF=BC=8C=E5=A6=82?= =?UTF-8?q?=E6=9E=9C=E6=96=87=E4=BB=B6=E4=B8=8D=E5=AD=98=E5=9C=A8=EF=BC=8C?= =?UTF-8?q?=E5=88=99=E8=BF=94=E5=9B=9Enull?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/utils/JsonUtil.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assets/core/utils/JsonUtil.ts b/assets/core/utils/JsonUtil.ts index 33d7ece..2a1f1c8 100644 --- a/assets/core/utils/JsonUtil.ts +++ b/assets/core/utils/JsonUtil.ts @@ -54,6 +54,9 @@ export class JsonUtil { resLoader.release(url); resolve(content.json); } + else { + resolve(null); + } } }); } -- Gitee From f78f0a274467f99490afbeecf8d45e4f6099ea96 Mon Sep 17 00:00:00 2001 From: dgflash Date: Thu, 18 Sep 2025 16:43:05 +0800 Subject: [PATCH 32/37] . --- assets/module/common/CCBusiness.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/module/common/CCBusiness.ts b/assets/module/common/CCBusiness.ts index be20d4a..d62e1e8 100644 --- a/assets/module/common/CCBusiness.ts +++ b/assets/module/common/CCBusiness.ts @@ -13,7 +13,7 @@ import { CCEntity } from "./CCEntity"; export class CCBusiness { ent!: CCEntity; - /** 业务逻辑初台化 */ + /** 业务逻辑初始化 */ protected init() { } @@ -27,7 +27,7 @@ export class CCBusiness { } //#region 全局事件管理 - + private _event: EventDispatcher | null = null; /** 全局事件管理器 */ private get event(): EventDispatcher { -- Gitee From 173d771110add15cc1a6def59e135467f5c64017 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 19 Sep 2025 15:59:07 +0800 Subject: [PATCH 33/37] =?UTF-8?q?=E4=BF=AE=E6=94=B9TimerManager=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/common/timer/TimerManager.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/core/common/timer/TimerManager.ts b/assets/core/common/timer/TimerManager.ts index 9700bf3..dc89178 100644 --- a/assets/core/common/timer/TimerManager.ts +++ b/assets/core/common/timer/TimerManager.ts @@ -82,7 +82,7 @@ export class TimerManager extends Component { start() { // 在指定对象上注册一个倒计时的回调管理器 - this.timeId = oops.timer.register(this, "countDown", this.onSecond, this.onComplete); + this.timeId = oops.timer.register(this, "countDown", this, this.onSecond, this.onComplete); } private onSecond() { @@ -94,7 +94,7 @@ export class TimerManager extends Component { } } */ - register(object: any, field: string, target: object, onSecond: Function, onComplete: Function): string { + register(object: any, field: string, target: object, onSecond?: Function, onComplete?: Function): string { const timer = new Timer(); timer.step = 1; @@ -121,7 +121,7 @@ export class TimerManager extends Component { * @param onSecond 每秒事件 * @param onComplete 倒计时完成事件 */ - addCallback(id: string, onSecond: Function, onComplete: Function) { + addCallback(id: string, onSecond?: Function, onComplete?: Function) { let data = this.times[id]; if (data) { if (onSecond) data.onSeconds.push(onSecond); -- Gitee From dcd1ef83409679df1a20f53d9cafaab7cda58057 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 19 Sep 2025 17:28:23 +0800 Subject: [PATCH 34/37] =?UTF-8?q?CCBusiness=E6=94=AF=E6=8C=81=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCBusiness.ts | 4 ++-- assets/module/common/CCEntity.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/module/common/CCBusiness.ts b/assets/module/common/CCBusiness.ts index d62e1e8..e8a6836 100644 --- a/assets/module/common/CCBusiness.ts +++ b/assets/module/common/CCBusiness.ts @@ -10,8 +10,8 @@ import { ListenerFunc } from "../../core/common/event/EventMessage"; import { CCEntity } from "./CCEntity"; /** 业务逻辑 */ -export class CCBusiness { - ent!: CCEntity; +export class CCBusiness { + ent!: T; /** 业务逻辑初始化 */ protected init() { diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index 0efd3b8..f33161e 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -119,14 +119,14 @@ export abstract class CCEntity extends ecs.Entity { //#region 游戏业务层管理 /** 模块业务逻辑组件 */ - private businesss: Map = null!; + private businesss: Map> = null!; /** * 批量添加组件 * @param ctors 组件类 * @returns */ - addBusinesss(...clss: any[]) { + addBusinesss>(...clss: any[]) { for (let ctor of clss) { this.addBusiness(ctor); } @@ -137,7 +137,7 @@ export abstract class CCEntity extends ecs.Entity { * @param cls 业务逻辑组件类 * @returns 业务逻辑组件实例 */ - addBusiness(cls: any): T { + addBusiness>(cls: any): T { if (this.businesss == null) this.businesss = new Map(); if (this.businesss.has(cls)) { console.error(`${cls.name} 业务逻辑组件已存在`); @@ -155,7 +155,7 @@ export abstract class CCEntity extends ecs.Entity { * @param cls 业务逻辑组件类 * @returns 业务逻辑组件实例 */ - getBusiness(cls: any): T { + getBusiness>(cls: any): T { return this.businesss.get(cls) as T; } -- Gitee From 21472de6bc0fb36b8a95129eae764868642acf4b Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 19 Sep 2025 17:49:52 +0800 Subject: [PATCH 35/37] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCCEntity=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E6=97=B6=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCEntity.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index f33161e..241a587 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -170,9 +170,16 @@ export abstract class CCEntity extends ecs.Entity { //#endregion destroy(): void { - this.singletons.clear(); - this.businesss.forEach(business => business.destroy()); - this.businesss.clear(); + if (this.singletons) { + this.singletons.clear(); + this.singletons = null!; + } + + if (this.businesss) { + this.businesss.forEach(business => business.destroy()); + this.businesss.clear(); + this.businesss = null!; + } super.destroy(); } } \ No newline at end of file -- Gitee From d120563ac43ded28c1b4592ebef47ac1c8e87df2 Mon Sep 17 00:00:00 2001 From: dgflash Date: Fri, 19 Sep 2025 23:02:53 +0800 Subject: [PATCH 36/37] =?UTF-8?q?CCView=E4=B8=8ECCViewVM=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/module/common/CCEntity.ts | 5 +++-- assets/module/common/CCView.ts | 6 +++--- assets/module/common/CCViewVM.ts | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/assets/module/common/CCEntity.ts b/assets/module/common/CCEntity.ts index 241a587..3f4dc74 100644 --- a/assets/module/common/CCEntity.ts +++ b/assets/module/common/CCEntity.ts @@ -12,6 +12,7 @@ import { CCView } from "./CCView"; import { CCViewVM } from "./CCViewVM"; export type ECSCtor = __private.__types_globals__Constructor | __private.__types_globals__AbstractedConstructor; +export type ECSView = CCViewVM | CCView; /** ECS 游戏模块实体 */ export abstract class CCEntity extends ecs.Entity { @@ -55,7 +56,7 @@ export abstract class CCEntity extends ecs.Entity { * @param path 显示资源地址 * @param bundleName 资源包名称 */ - addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { + addPrefab(ctor: ECSCtor, parent: Node, path: string, bundleName: string = resLoader.defaultBundleName) { const node = ViewUtil.createPrefabNode(path, bundleName); const comp = node.getComponent(ctor)!; this.add(comp); @@ -68,7 +69,7 @@ export abstract class CCEntity extends ecs.Entity { * @param params 界面参数 * @returns 界面节点 */ - addUi(ctor: ECSCtor, params?: UIParam): Promise { + addUi(ctor: ECSCtor, params?: UIParam): Promise { return new Promise(async (resolve, reject) => { const key = gui.internal.getKey(ctor); if (key) { diff --git a/assets/module/common/CCView.ts b/assets/module/common/CCView.ts index 7d93c31..01ccbe5 100644 --- a/assets/module/common/CCView.ts +++ b/assets/module/common/CCView.ts @@ -24,7 +24,7 @@ import { GameComponent } from './GameComponent'; * @example @ccclass('RoleViewComp') @ecs.register('RoleView', false) -export class RoleViewComp extends CCView { +export class RoleViewComp extends CCView { @property({ type: sp.Skeleton, tooltip: '角色动画' }) spine: sp.Skeleton = null!; @@ -33,12 +33,12 @@ export class RoleViewComp extends CCView { } } */ -export abstract class CCView extends GameComponent implements ecs.IComp { +export abstract class CCView extends GameComponent implements ecs.IComp { static tid: number = -1; static compName: string; canRecycle!: boolean; - ent!: CCEntity; + ent!: T; tid: number = -1; /** 从父节点移除自己 */ diff --git a/assets/module/common/CCViewVM.ts b/assets/module/common/CCViewVM.ts index c394e14..6f1219c 100644 --- a/assets/module/common/CCViewVM.ts +++ b/assets/module/common/CCViewVM.ts @@ -25,7 +25,7 @@ import { CCEntity } from './CCEntity'; * @example @ccclass('LoadingViewComp') @ecs.register('LoadingView', false) -export class LoadingViewComp extends CCViewVM { +export class LoadingViewComp extends CCViewVM { // VM 组件绑定数据 data: any = { // 加载资源当前进度 @@ -45,12 +45,12 @@ export class LoadingViewComp extends CCViewVM { } } */ -export abstract class CCViewVM extends VMParent implements ecs.IComp { +export abstract class CCViewVM extends VMParent implements ecs.IComp { static tid: number = -1; static compName: string; canRecycle!: boolean; - ent!: CCEntity; + ent!: T; tid: number = -1; /** 从父节点移除自己 */ -- Gitee From cc5f86cfdafe6631ff95fb6f487a93e2e5cb60f7 Mon Sep 17 00:00:00 2001 From: dgflash Date: Sat, 20 Sep 2025 21:58:55 +0800 Subject: [PATCH 37/37] . --- assets/libs/gui/button/ButtonSimple.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/libs/gui/button/ButtonSimple.ts b/assets/libs/gui/button/ButtonSimple.ts index b66216f..a96b0b9 100644 --- a/assets/libs/gui/button/ButtonSimple.ts +++ b/assets/libs/gui/button/ButtonSimple.ts @@ -59,7 +59,7 @@ export default class ButtonSimple extends Component { } /** 短按触摸音效 */ - protected async playEffect() { + protected playEffect() { if (ButtonSimple.effectPath) { oops.audio.playEffect(ButtonSimple.effectPath); } -- Gitee