From b3c2cbfc4ba625aa24905440783ace318bf94ae6 Mon Sep 17 00:00:00 2001 From: dgflash Date: Tue, 25 Mar 2025 20:53:43 +0800 Subject: [PATCH] =?UTF-8?q?GUI=E6=A1=86=E6=9E=B6=E5=B1=82=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E6=94=AF=E6=8C=81=E5=A4=96=E9=83=A8=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/core/Root.ts | 44 +++--- assets/core/gui/layer/LayerManager.ts | 206 +++++++++++++------------- 2 files changed, 127 insertions(+), 123 deletions(-) diff --git a/assets/core/Root.ts b/assets/core/Root.ts index 95c0b69..bcc5fad 100644 --- a/assets/core/Root.ts +++ b/assets/core/Root.ts @@ -45,59 +45,57 @@ export class Root extends Component { if (!isInited) { isInited = true; // 注:这里是规避cc3.8在编辑器模式下运行时,关闭游戏会两次初始化报错 - console.log(`Oops Framework v${version}`); + console.log(`Oops Framework ${version}`); this.enabled = false; + + this.initModule(); this.iniStart(); this.loadConfig().then(); } } - private async loadConfig() { + private initModule() { // 创建持久根节点 this.persist = new Node("OopsFrameworkPersistNode"); director.addPersistRootNode(this.persist); - + // oops.config.btc = new BuildTimeConstants(); + // Web平台查询参数管理 + oops.config.query = new GameQueryConfig(); // 资源管理模块 oops.res = resLoader; + // 全局消息 + oops.message = message; + // 创建时间模块 + oops.timer = this.persist.addComponent(TimerManager)!; + // 游戏场景管理 + oops.game = new GameManager(this.game); + // 创建游戏界面管理对象 + oops.gui = new LayerManager(); + } + private async loadConfig() { const config_name = "config"; const config = await oops.res.loadAsync(config_name, JsonAsset); if (config) { - // oops.config.btc = new BuildTimeConstants(); - oops.config.query = new GameQueryConfig(); oops.config.game = new GameConfig(config); - // 设置默认资源包 - oops.res.defaultBundleName = oops.config.game.bundleDefault; - oops.res.init(oops.config.game.data.bundle); - // 本地存储模块 oops.storage = new StorageManager(); oops.storage.init(new StorageSecuritySimple); // oops.storage.init(new StorageSecurityCrypto); - // 全局消息 - oops.message = message; - // 创建音频模块 oops.audio = this.persist.addComponent(AudioManager); oops.audio.load(); - // 创建时间模块 - oops.timer = this.persist.addComponent(TimerManager)!; - - // 游戏场景管理 - oops.game = new GameManager(this.game); + // 设置默认资源包 + oops.res.defaultBundleName = oops.config.game.bundleDefault; + oops.res.init(oops.config.game.data.bundle); // 游戏界面管理 - oops.gui = new LayerManager(); oops.gui.mobileSafeArea = oops.config.game.mobileSafeArea; //@ts-ignore - oops.gui.initLayer(this.gui); - - // 网络模块 - oops.http.server = oops.config.game.httpServer; // Http 服务器地址 - oops.http.timeout = oops.config.game.httpTimeout; // Http 请求超时时间 + oops.gui.initLayer(this.gui, config.json.gui); // 初始化每秒传输帧数 game.frameRate = oops.config.game.frameRate; diff --git a/assets/core/gui/layer/LayerManager.ts b/assets/core/gui/layer/LayerManager.ts index 64da0ae..4883fd4 100644 --- a/assets/core/gui/layer/LayerManager.ts +++ b/assets/core/gui/layer/LayerManager.ts @@ -29,12 +29,26 @@ export enum LayerType { Dialog = "LayerDialog", /** 系统触发模式窗口层 */ System = "LayerSystem", - /** 滚动消息提示层 */ + /** 消息提示层 */ Notify = "LayerNotify", /** 新手引导层 */ Guide = "LayerGuide" } +/** 界面层组件类型 */ +export enum LayerTypeCls { + /** 主界面层 */ + UI = "UI", + /** 弹窗层 */ + PopUp = "PopUp", + /** 模式窗口层 */ + Dialog = "Dialog", + /** 消息提示层 */ + Notify = "Notify", + /** 自定义节点层 */ + Node = "Node" +} + /** * 界面配置结构体 * @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037986&doc_id=2873565 @@ -58,7 +72,7 @@ export interface UIConfig { /** 远程包名 */ bundle?: string; /** 窗口层级 */ - layer: LayerType; + layer: string; /** 预制资源相对路径 */ prefab: string; /** 是否自动施放(默认不自动释放) */ @@ -71,6 +85,8 @@ export interface UIConfig { mask?: boolean; /** 是否启动真机安全区域显示 */ safeArea?: boolean; + /** 界面弹出时的节点排序索引 */ + siblingIndex?: number; } /** 界面层级管理器 */ @@ -91,43 +107,72 @@ export class LayerManager { /** 是否开启移动设备安全区域适配 */ mobileSafeArea: boolean = false; - /** 界面层 */ - private ui!: LayerUI; - /** 弹窗层 */ - private popup!: LayerPopUp; - /** 只能弹出一个的弹窗 */ - private dialog!: LayerDialog; - /** 游戏系统提示弹窗 */ - private system!: LayerDialog; /** 消息提示控制器,请使用show方法来显示 */ private notify!: LayerNotify; /** UI配置 */ private configs: { [key: number]: UIConfig } = {}; + /** 界面层集合 - 无自定义类型 */ + private uiLayers: Map = new Map(); + /** 界面层组件集合 */ + private clsLayers: Map = new Map(); + + constructor() { + this.clsLayers.set(LayerTypeCls.UI, LayerUI); + this.clsLayers.set(LayerTypeCls.PopUp, LayerPopUp); + this.clsLayers.set(LayerTypeCls.Dialog, LayerDialog); + this.clsLayers.set(LayerTypeCls.Notify, LayerNotify); + this.clsLayers.set(LayerTypeCls.Node, null); + } + + /** + * 注册自定义界面层对象 + * @param type 自定义界面层类型 + * @param cls 自定义界面层对象 + */ + registerLayerCls(type: string, cls: any) { + if (this.clsLayers.has(type)) { + console.error("已存在自定义界面层类型", type); + return; + } + this.clsLayers.set(type, cls); + } /** * 初始化界面层 * @param root 界面根节点 */ - private initLayer(root: Node) { + private initLayer(root: Node, config: any) { + if (config == null) { + console.error("请升级到最新版本框架,界面层级管理修改为数据驱动。参考模板项目中的config.json配置文件"); + return; + } this.root = root; this.initScreenAdapter(); this.camera = this.root.getComponentInChildren(Camera)!; - this.game = this.create_node(LayerType.Game); - this.ui = new LayerUI(LayerType.UI); - this.popup = new LayerPopUp(LayerType.PopUp); - this.dialog = new LayerDialog(LayerType.Dialog); - this.system = new LayerDialog(LayerType.System); - this.notify = new LayerNotify(LayerType.Notify); - this.guide = this.create_node(LayerType.Guide); + // 创建界面层 + for (let i = 0; i < config.length; i++) { + let data = config[i]; + let layer: Node = null!; + if (data.type == LayerTypeCls.Node) { + layer = this.create_node(data.name); + } + else { + let cls = this.clsLayers.get(data.type); + if (cls) { + layer = new cls(data.name); + } + else { + console.error("未识别的界面层类型", data.type); + } + } + root.addChild(layer); - root.addChild(this.game); - root.addChild(this.ui); - root.addChild(this.popup); - root.addChild(this.dialog); - root.addChild(this.system); - root.addChild(this.notify); - root.addChild(this.guide); + if (layer instanceof LayerUI) + this.uiLayers.set(data.name, layer); + else if (layer instanceof LayerNotify) + this.notify = layer; + } } /** 初始化屏幕适配 */ @@ -171,7 +216,9 @@ export class LayerManager { * @param callback 回调方法 */ setOpenFailure(callback: Function) { - this.ui.onOpenFailure = this.popup.onOpenFailure = this.dialog.onOpenFailure = this.system.onOpenFailure = callback; + this.uiLayers.forEach((layer: LayerUI) => { + layer.onOpenFailure = callback; + }) } /** @@ -182,6 +229,7 @@ export class LayerManager { * oops.gui.toast("提示内容"); */ toast(content: string, useI18n: boolean = false) { + this.notify.toast(content, useI18n) } @@ -227,19 +275,12 @@ export class LayerManager { return; } - switch (config.layer) { - case LayerType.UI: - this.ui.add(config, uiArgs, callbacks); - break; - case LayerType.PopUp: - this.popup.add(config, uiArgs, callbacks); - break; - case LayerType.Dialog: - this.dialog.add(config, uiArgs, callbacks); - break; - case LayerType.System: - this.system.add(config, uiArgs, callbacks); - break; + let layer = this.uiLayers.get(config.layer); + if (layer) { + layer.add(config, uiArgs, callbacks); + } + else { + console.error(`打开编号为【${uiId}】的界面失败,界面层不存在`); } } @@ -313,19 +354,12 @@ export class LayerManager { } var result = false; - switch (config.layer) { - case LayerType.UI: - result = this.ui.has(config.prefab); - break; - case LayerType.PopUp: - result = this.popup.has(config.prefab); - break; - case LayerType.Dialog: - result = this.dialog.has(config.prefab); - break; - case LayerType.System: - result = this.system.has(config.prefab); - break; + let layer = this.uiLayers.get(config.layer); + if (layer) { + result = layer.has(config.prefab); + } + else { + console.error(`验证编号为【${uiId}】的界面失败,界面层不存在`); } return result; @@ -345,19 +379,12 @@ export class LayerManager { } let result: Node = null!; - switch (config.layer) { - case LayerType.UI: - result = this.ui.get(config.prefab); - break; - case LayerType.PopUp: - result = this.popup.get(config.prefab); - break; - case LayerType.Dialog: - result = this.dialog.get(config.prefab); - break; - case LayerType.System: - result = this.system.get(config.prefab); - break; + let layer = this.uiLayers.get(config.layer); + if (layer) { + result = layer.get(config.prefab); + } + else { + console.error(`获取编号为【${uiId}】的界面失败,界面层不存在`); } return result; } @@ -376,19 +403,12 @@ export class LayerManager { return; } - switch (config.layer) { - case LayerType.UI: - this.ui.remove(config.prefab, isDestroy); - break; - case LayerType.PopUp: - this.popup.remove(config.prefab, isDestroy); - break; - case LayerType.Dialog: - this.dialog.remove(config.prefab, isDestroy); - break; - case LayerType.System: - this.system.remove(config.prefab, isDestroy); - break; + let layer = this.uiLayers.get(config.layer); + if (layer) { + layer.remove(config.prefab, isDestroy); + } + else { + console.error(`移除编号为【${uiId}】的界面失败,界面层不存在`); } } @@ -405,27 +425,14 @@ export class LayerManager { if (comp && comp.vp) { // 释放显示的界面 if (node.parent) { - (node.parent as LayerUI).remove(comp.vp.config.prefab, isDestroy); + this.uiLayers.get(LayerType.UI)!.remove(comp.vp.config.prefab, isDestroy); } // 释放缓存中的界面 else if (isDestroy) { - switch (comp.vp.config.layer) { - case LayerType.UI: - // @ts-ignore 注:不对外使用 - this.ui.removeCache(comp.vp.config.prefab); - break; - case LayerType.PopUp: - // @ts-ignore 注:不对外使用 - this.popup.removeCache(comp.vp.config.prefab); - break; - case LayerType.Dialog: - // @ts-ignore 注:不对外使用 - this.dialog.removeCache(comp.vp.config.prefab); - break; - case LayerType.System: - // @ts-ignore 注:不对外使用 - this.system.removeCache(comp.vp.config.prefab); - break; + let layer = this.uiLayers.get(comp.vp.config.layer); + if (layer) { + // @ts-ignore 注:不对外使用 + layer.removeCache(comp.vp.config.prefab); } } } @@ -443,10 +450,9 @@ export class LayerManager { * oops.gui.clear(); */ clear(isDestroy: boolean = false) { - this.ui.clear(isDestroy); - this.popup.clear(isDestroy); - this.dialog.clear(isDestroy); - this.system.clear(isDestroy); + this.uiLayers.forEach((layer: LayerUI) => { + layer.clear(isDestroy); + }) } private create_node(name: string) {