Gui框架支持通过gui.register注册界面配置

This commit is contained in:
dgflash
2025-09-09 17:19:57 +08:00
parent dfe27e7442
commit b4ea586d1a
13 changed files with 203 additions and 43 deletions

31
assets/core/gui/Gui.ts Normal file
View File

@@ -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];
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.24",
"importer": "typescript",
"imported": true,
"uuid": "51e09b11-d9ab-453b-b637-74d6aa615806",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -51,4 +51,4 @@ export enum LayerTypeCls {
Game = "Game",
/** 自定义节点层 */
Node = "Node"
}
}

View File

@@ -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<string, LayerUI> = 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);
}
// 释放缓存中的界面

View File

@@ -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 {
/**

View File

@@ -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 {

View File

@@ -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;
/**
* 组件被回收时会调用这个接口。可以在这里重置数据,或者解除引用

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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<T extends ecs.Comp> = __private.__types_globals__Constructor<T> | __private.__types_globals__AbstractedConstructor<T>;
export class ModuleUtil {
/**
* 异步添加视图层组件
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param uiArgs 界面参数
* @returns 界面节点
*/
static add<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>((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<ecs.IComp>, 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<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, 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<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, 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<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, uiId: Uiid, uiArgs: any = null): Promise<Node | null> {
return new Promise<Node | null>((resolve, reject) => {
@@ -54,21 +141,6 @@ export class ModuleUtil {
});
}
/**
* 通过资源内存中获取预制上的组件添加到ECS实体中
* @param ent 模块实体
* @param ctor 界面逻辑组件
* @param parent 显示对象父级
* @param url 显示资源地址
* @param bundleName 资源包名称
*/
static addView<T extends CCVMParentComp | CCComp>(ent: ecs.Entity, ctor: ECSCtor<T>, 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<ecs.IComp>, uiId: Uiid, isDestroy: boolean = true, onRemoved?: Function) {
const node = oops.gui.get(uiId);

View File

@@ -6,6 +6,7 @@
*/
import { oops } from "../../core/Oops";
/** 游戏自定义参数分组类型 */
export enum GameConfigCustomType {
/** 开发环境 */
Dev = "dev",