用Unity同时开发【微信小游戏】【安卓】【IOS】游戏#5.5.1 窗口管理器
【系列文章目錄】
文章目錄
- 【系列文章目錄】
- 前言
- 一、顯示普通窗口
- 1.使用PuerTS創建一個FGUI窗口
- 2.拓展窗口基類
- 3.創建拓展窗口
- 二、顯示彈出窗口
- 三、管理窗口的創建、顯示、隱藏、銷毀
- 四、在WebGL與微信小游戲中
前言
本篇我們來創建FGUI的窗口管理類
一、顯示普通窗口
1.使用PuerTS創建一個FGUI窗口
FGUI文檔中有關于窗口系統的描述【FGUI文檔——窗口系統】
按照文檔中的說法
我們在創建一個高層級的組件的時候
不應該直接將組件放在GRoot下(FGUI的根節點)
而是應該先創建窗口再放置這些組件
首先我們創建一個UI管理器,并為他添加以下方法
public static async ShowWnd(pkg: string,name: string) {//異步加載FGUI包資源await $promise(API.LoadFairyGUIPackage(pkg));//創建窗口let win: FairyGUI.Window = new FairyGUI.Window();//創建窗口內容win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;//全屏顯示win.MakeFullScreen();//顯示窗口win.Show(); }使用上面的方法我們就可以創建一個窗口并將組件作為窗口中的內容放在窗口中顯示
這樣我們通過窗口的API可以更容易的控制界面
2.拓展窗口基類
我們可以使用FGUI的窗口可以作為基類,進行拓展
export interface IGwndController extends IController {//窗口的拓展接口 }export abstract class AbstractGWndController extends FairyGUI.Window implements IGwndController{//窗口的拓展實現 }這樣我們就拓展好了FGUI的窗口
3.創建拓展窗口
在游戲中,我希望每個窗口都有自己的類
而上面的抽象類只作為一個模板存在
export class WndLogin extends AbstractGWndController{//具體窗口的實現 }這樣我們就擁有了實際窗口類,他們與FGUI編輯器中我們所設計的界面一一對應
所以我們需要將他們的對于關系存儲起來
先思考一個我們需要一個什么樣的結構
- key:用于創建窗口時索引窗口信息的值,唯一
- pkgName:組件所在包名
- itemId:組件名
- script:窗口類
- windName:窗口名
這樣我們就先定義了一個接口類型
export interface IUIInfo {pkgName: stringitemId: stringscript: anywindName: string }然后我們建了一個類專門用于管理窗口信息與組件拓展信息
export class UITable {public static UIWindow = {WndGameMain: { pkgName: "GameMain", itemId: "WndGameMain", script: WndGameMain, windName: "WndGameMain" },WndLogin: { pkgName: "Login", itemId: "WndLogin", script: WndLogin, windName: "WndLogin" },} }這樣我們在需要創建窗口的時候只需要填入窗口名,就可以把窗口創建出來了,修改以下窗口創建函數
public static async ShowWnd(windName: string) {let info: IUIInfo = UITable.UIWindow[windName]//判斷是否存在窗口信息if (info != null) {let pkg = info.pkgNamelet name = info.itemIdlet scr = info.scriptlet wndName = info.windName//異步加載FGUI包資源await $promise(API.LoadFairyGUIPackage(pkg))//創建窗口let win: AbstractGWndController = new scr();win.name = wndName;//創建窗口內容win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;win.MakeFullScreen();//綁定子組件(這個方法自行拓展)win.BindChild(win);FairyGUI.GRoot.inst.ShowWindow(win);}else {TSLog.Error("WindowName:【" + windName + "】 does not exist or is misspelled,Please check the spelling");} }這樣我們就可以通過我們自己的UI管理器創建出一個我們自己拓展的窗口了
二、顯示彈出窗口
接下來我們來做彈出窗口即點擊空白區域會自動關閉的窗口
首先,不要總想著自己一個人造車,先翻一下FGUI文檔吧
于是我在FGUI的文檔中找到了【FGUI文檔——Popup】的內容
按照文檔中的描述,十分的簡單
顯示普通窗口我們用的是
窗口類中Show()的方法
而顯示彈出窗口我們只需要把需要這個效果的窗口作為參數傳入
FairyGUI.GRoot.inst.ShowPopup()這個方法就可以了
由于創建窗口的部分與普通窗口時公用的,所以我將它分離出來
//有窗口返回窗口,無窗口創建窗口 private async GetWnd(windName: string): Promise<AbstractGWndController> {let info: IUIInfo = UITable.UIWindow[windName]if (info == null) {TSLog.Error("WindowName:【" + windName + "】 does not exist or is misspelled,Please check the spelling");return null;}try {if (this.HasWnd(windName)) {return this.Map_WndInstance.get(windName);}else {let pkg = info.pkgNamelet name = info.itemIdlet scr = info.scriptlet wndName = info.windName//異步加載FGUI包資源await $promise(API.LoadFairyGUIPackage(pkg))//創建窗口let win: AbstractGWndController = new scr();win.name = wndName;//創建窗口內容win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;win.MakeFullScreen();//綁定代碼win.fui = win.contentPane;win.BindAll(win);//存儲窗口對象this.Map_WndInstance.set(windName, win);return win;}}catch {TSLog.Error("WindowName:【" + windName + "】 throw error when create");}return null; }將顯示普通窗口的方法修改一下
public async ShowWnd(windName: string, modal: boolean = true) {let wnd: AbstractGWndController = await this.GetWnd(windName);if (wnd == null) {TSLog.Error("WindowName:【" + windName + "】 can not get this window");}wnd.modal = modal;FairyGUI.GRoot.inst.ShowWindow(wnd); }然后接下來只需要寫一個彈出窗口的方法就可以了
public async ShowPopWnd(windName: string, modal: boolean = true) {let wnd: AbstractGWndController = await this.GetWnd(windName);if (wnd == null) {TSLog.Error("WindowName:【" + windName + "】 can not get this window");}LinxLog.Log("PopWnd")wnd.modal = modal;FairyGUI.GRoot.inst.ShowPopup(wnd); }似乎這樣就可以了
然而在測試的時候我發現好像并不能點擊空白處關閉窗口
我的組件時這樣的
研究了一下發現,我需要把組件屬性中的點擊穿透開起來才可以
而在這過程中,我還發現了FGUI為我們做好了黑遮的效果
只需要在窗口中將modal這個屬性設為true就可以了
這個功能一樣要把組件中的點擊穿透開啟才會生效
這樣才一個窗口內的空白區域,會被modal遮擋,阻止穿透到其他的窗口
三、管理窗口的創建、顯示、隱藏、銷毀
按照上述方式來創建顯示窗口
我們會使用一個Map來存儲已經存在的窗口
public Map_WndInstance: Map<string, AbstractGWndController> = new Map<string, AbstractGWndController>();這樣我們做隱藏和銷毀就很容易了
//隱藏窗口public HideWnd(windName: string) {if (this.HasWnd(windName)) {let wnd = this.Map_WndInstance.get(windName);FairyGUI.GRoot.inst.HideWindow(wnd);} }//隱藏彈窗 public HidePopWnd(windName: string) {if (this.HasWnd(windName)) {let wnd = this.Map_WndInstance.get(windName);FairyGUI.GRoot.inst.HidePopup(wnd);} }//銷毀窗口 public DisposeWnd(windName: string) {if (this.HasWnd(windName)) {let wnd = this.Map_WndInstance.get(windName);wnd.Dispose();this.Map_WndInstance.delete(windName);} }四、在WebGL與微信小游戲中
由于Unity導出的WebGL中是不支持異步的
所以如果有導出WebGL或微信小游戲的計劃
那就不要使用異步方法,而是用回調的方式來做
可以參考下面的方式:
//第一步、外部調用顯示窗口public ShowWnd(windName: string, modal: boolean = true): void {//獲取配置let info: IUIInfo = UITable.UIWindow[windName]//查詢不到配置拋出錯誤if (info == null) {TSLog.Error("WindowName:【" + windName + "】 does not exist or is misspelled,Please check the spelling");return;}//構造窗口數據let wnddata: UIWndData = { windName: windName, cfg: info, modal: modal }//通往第二步,獲取窗口并指定最終步驟this.GetWnd(wnddata, this.DoShowWnd.bind(this));}//內部調用,有窗口返回窗口,無窗口創建窗口private GetWnd(info: UIWndData, call: Function): void {try {//判斷是否已存在窗口if (this.HasWnd(info.windName)) {if (call != null) {//窗口已存在通往最終步驟call(info, this.Map_WndInstance.get(info.windName))};}else {let pkg = info.cfg.pkgName//加載FGUI包資源,加載完成通完第三步API.LoadFairyGUIPackage(pkg, this.LoadPackComplete.bind(this, info, call))}}catch (error) {TSLog.Error("WindowName:【" + info.windName + "】 throw error when create");TSLog.Error("error:" + error);}}//第三步、加載完成回調private LoadPackComplete(info: UIWndData, call: Function): void {let pkg = info.cfg.pkgNamelet name = info.cfg.itemIdlet scr = info.cfg.scriptlet wndName = info.windName//創建窗口let win: AbstractGWndController = new scr();win.name = wndName;//創建窗口內容win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;win.MakeFullScreen();//綁定代碼win.fui = win.contentPane;win.BindAll(win);//存儲窗口對象this.Map_WndInstance.set(info.windName, win);if (call != null) {//通往最終步驟call(info, win)};}//最終步驟、加載完成回調,顯示窗口private DoShowWnd(info: UIWndData, wnd: AbstractGWndController) {let wndName = info.windNamelet modal = info.modalif (wnd == null) {TSLog.Error("WindowName:【" + wndName + "】 can not get this window");}wnd.modal = modal;FairyGUI.GRoot.inst.ShowWindow(wnd);}這樣在微信小游戲中就可以正常的運行了
這里之所以不用匿名函數,是因為使用匿名函數會造成GC的問題
所以使用了命名函數,雖然寫起來麻煩而且很長
對比之下,異步的方式,真是清爽
總結
以上是生活随笔為你收集整理的用Unity同时开发【微信小游戏】【安卓】【IOS】游戏#5.5.1 窗口管理器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初级基础HTML CSS实现二级下拉菜单
- 下一篇: 全志问题解决方法