千鋒教育-做有情懷、有良心、有品質的職業教育機構
前言
xlua-framework
xlua-framework-unity2018
我們前面說過xlua-framework這個框架,是一個純lua的一個框架,也就是說我們所有的邏輯都可以在lua中實現,只有資源模塊和網絡模塊是c#原生寫的,但是也在lua中給我們包裝的工具類,讓我們更方便的使用。在框架的純lua代碼中,不得不說,ui框架是我最喜歡的,一套基于mvc的一套ui框架。
MVC框架
說到MVC框架,很多人可能會說,mvc根本就不適合游戲,有這種想法的人,一定是個編程新手,我們在介紹UI框架前,先來介紹下MVC。
首先,mvc,是一種編程思想或者說框架思想,并不是一個設計模式,而這種思想的核心是分層,也就是說,我們要把ui相關的界面顯示和ui數據存儲以及ui控制邏輯分開不同的文件來寫,為什么要分層呢?這和Web的mvc思想是一致的,都是為了降低我們類的復雜度,方便我們閱讀和擴展,如下圖所示:
比如說,一個復雜的UI頁面類,有2000多行代碼。如果我們代碼結構寫的不好,會發現這個類很難維護,也很難擴展,甚至連閱讀都很難,接下來我們針對上面這個UI做一個小優化:我們把UI控件顯示相關的函數,獨立到一個View類中,數據相關的放到Model類中,控制輸入相關的放到Ctrl類中。接下來我們這個頁面就很容易擴展和閱讀了,比如我們只是修改ui顯示相關的,那我們之控制View類就行了,大概也就4-5百行左右的代碼,很好維護,同理,如果是想修改用戶輸入控制的方法,直接修改Ctrl類就行了,如果只是處理UI顯示的數據相關,直接修改Model類中對數據整理相關的函數就可以了。
MVC的變體
1.MVC(Model-View-Controller)
MVC是比較直觀的架構模式,用戶操作->View(負責接收用戶的輸入操作)->Controller(業務邏輯處理)->Model(數據持久化)->View(將結果反饋給View)。
MVC使用非常廣泛,比如JavaEE中的SSH框架(Struts/Spring/Hibernate),Struts(View, STL)-Spring(Controller, Ioc、Spring MVC)-Hibernate(Model, ORM)以及ASP.NET中的ASP.NET MVC框架,xxx.cshtml-xxxcontroller-xxxmodel。
2.MVP(Model-View-Presenter)
MVP是把MVC中的Controller換成了Presenter(呈現),目的就是為了完全切斷View跟Model之間的聯系,由Presenter充當橋梁,做到View-Model之間通信的完全隔離。
.NET程序員熟知的ASP.NET webform、winform基于事件驅動的開發技術就是使用的MVP模式??丶M成的頁面充當View,實體數據庫操作充當Model,而View和Model之間的控件數據綁定操作則屬于Presenter??丶录奶幚砜梢酝ㄟ^自定義的IView接口實現,而View和IView都將對Presenter負責。
3.MVVM(Model-View-ViewModel)
如果說MVP是對MVC的進一步改進,那么MVVM則是思想的完全變革。它是將“數據模型數據雙向綁定”的思想作為核心,因此在View和Model之間沒有聯系,通過ViewModel進行交互,而且Model和ViewModel之間的交互是雙向的,因此視圖的數據的變化會同時修改數據源,而數據源數據的變化也會立即反應到View上。
這方面典型的應用有.NET的WPF,js框架Knockout、AngularJS等。
xluaframework的MVC結構
當請求UI管理器打開窗口時,UI管理器會根據UI配置找到MVC各層腳本文件并實例化對象,生成一個UIWindow,一個window包含了View,Model,Ctrl三個組件,但是也不是一定modle和ctrl都要有,如果你的頁面非常簡單,可以沒有Model和Ctrl,或者只有Model沒有Ctrl,只有Ctrl沒有Model都可以。但是標準的頁面我們是需要MVC相互配合來實現的。
View層:負責界面所有UI刷新操作,只和展示相關的數據放在這,只有操作相關數據放Model去
注意:
1、被動刷新:所有界面刷新通過消息驅動—除了打開界面時的刷新
2、對Model層可讀,不可寫—調試模式下強制
3、所有寫數據、游戲控制操作、網絡相關操作全部放Ctrl層
4、Ctrl層不依賴View層,但是依賴Model層
5、任何情況下不要在游戲邏輯代碼操作界面刷新—除了打開、關閉界面
Model層:負責界面相關數據,同時負責消息定制和分發
注意:
1、數據大體分為兩類:游戲邏輯數據、界面控制數據
2、游戲邏輯數據:從游戲數據中心取數據,這里不做為數據源,只做中轉和必要處理(如排序),游戲中心數據改動以后在這里監聽變化
3、界面控制數據:一般會影響到多個界面展示的控制數據,登陸界面顯示當前服務器,當受到選服界面操作的影響
4、界面Model層對View層是只讀不寫的,一定不要在View層寫Model
5、界面Model層不依賴Ctrl層和View層,意思是說拿掉這這兩層代碼,Model依舊能完好運行
6、界面Model層數據只影響UI,不影響游戲邏輯,游戲邏輯不能從Model層取數據,意思是沒有界面,游戲依舊能跑
Ctrl層:負責發送網絡請求(網絡數據)、操作游戲邏輯、修改模型數據(本地數據)
注意:
1、UI控制層用于銜接Model層和View層,主要是用來修改數據,或者進行游戲邏輯控制
2、修改數據:界面操作相關數據直接寫Model層、游戲邏輯相關數據寫數據中心
3、游戲控制:發送網絡請求、調用游戲控制邏輯函數
4、Ctrl層是無狀態的,不能保存變量–調試模式下強制
UI腳本目錄結構
分成兩個部分:LuaScripts/Framework/UI為UI框架代碼,LuaScripts/UI為UI邏輯代碼。其中:
LuaScripts/Framework/UI/Base:基類
LuaScripts/Framework/UI/Component:UI組件
LuaScripts/Framework/UI/Message:UI消息定義
LuaScripts/Framework/UI/Util:UI工具類
LuaScripts/ UI/Config:窗口配置
LuaScripts/ UI/UIxxx:UI邏輯模塊,其中:Controller、Model、View對應控制、模型、視圖腳本;而UIxxxConfig為模塊配置腳本
UI模塊添加流程
拼預設:如AssetsPackage/ UI/ Prefabs/ View/ UILogin.prefab
UI名配置:LuaScripts/ UI/Config/ UIWindowNames中添加
導入配置:LuaScripts/ UI/Config/ UIConfig中添加
腳本配置:LuaScripts/ UI/UIxxx/UIxxxConfig中配置,需要注意的是:Model、Ctrl、View層如果沒有實現腳本,則直接填寫nil;PrefabPath為相對于AssetsPackage目錄的路徑,需要帶文件名后綴
在原框架xluaframework中,沒有帶ui的的自動創建工具,我們可以參考issues#39加一個工具加一個,xluaframework-unity2018的版本中已經帶了這個工具,我們直接在菜單欄的Tools->MVC Tools打開UI創建面板
我們只需要根據自己的需要填上UI的名字和文件夾名字,然后選擇是否需要Model和Ctrl,以及屬于哪個層,最后點擊CreateUILuaData按鈕即可。
UI工作流程
當請求UI管理器打開窗口時,UI管理器會根據UI配置找到MVC各層腳本文件并實例化對象,生成一個UIWindow的數據結構標識一個窗口。立刻調度Model層OnEnable(首次打開先調用OnCreate),如果有傳入參數,需要在此處保存下來;隨后等待UI資源異步加載完畢,加載完畢后調度View層OnEnable(同樣首次打開先調用OnCreate),View層隨后實現類似Mono腳本的調度流程,View層可以隨時讀取Model層數據,但是寫Model層數據需要經過Ctrl層;Ctrl層是無狀態的,如果需要狀態,寫Model層就好。
腳本調度順序:
OnCreate->OnEnable->Update->LateUpdate->OnDisable->OnDestroy
注意:Update相關函數添加上就會被調度,盡量不用,節省性能。界面邏輯書寫流程和寫Mono腳本大概一致。
數據流
A) 打開窗口時傳入數據:OnEnable中傳入Model層保存
B) Model層在OnEnable中從其他管理類或者數據類取數據并處理
C) View層可存放自身控制數據,直接讀、間接寫Model層數據
D) 模塊與模塊之間數據交換使用消息系統
注意:更多參考MVC各個實現腳本中的說明;技術細節直接參考源代碼。
UI組件系統
為了實現類似Mono腳本的函數調度,做了一個組件系統,腳本目錄在LuaScripts/Framework/UI/Component。組件大概分為兩種:基礎組件、容器組件。
基礎組件是對Unity側原生UI組件的封裝,這層封裝其實不要也行,只是封裝后有些操作使用起來更加方便,比如圖集圖片切換;容器組件用于組合管理多個基礎組件,并負責其中基礎組件的函數調度。
基礎組件:
UIButton,UICanvas,UIEffect,UIImage, UILayer,UIInput,UISlider,UIText,不做介紹,自己看源碼
容器組件:
UITabGroup,UIButtonGroup,UIWrapGroup,不做介紹,自己看源碼
自定義組件:
這里的自定義組件是指繼承了UIBaseComponent的類,相當于子模塊組件,對于十分復雜的UI界面,可以將模塊獨立的部分分離出來,寫一個Component腳本(繼承自UIBaseContainer),如主界面的小地圖,如背包中的某個Item。這個Component類似Unity中的Mono腳本,掛上去就能用。
使用示例參考選服界面服務器列表中每個Item的刷新邏輯,那里把每個Item當做了一個Component去刷新。
View層腳本:
View層腳本是最上層的容器組件,管理視圖中所有組件的調度。
特別需要注意的一點是:凡是Unity中的對象,在lua中進行判空時,不能直接判斷是否等于nil,而必須使用IsNull方法來判斷,這一點在XLua文檔中也提到過。
UI層級管理
UI層級下的所有窗口根據OderInLayer的值來前后排布,為了避免層級混亂,這里進行統一管理,劃分了一個子層級的概念,專供UI使用:
目前一共劃分了6個子層級,第一個LuanchLayer只在啟動界面使用;其余的子層級從上到下,展示時依次從背面到前面。
SceneLayer:用于場景UI
BackgroudLayer:背景UI
NormalLayer:普通一級、二級、三級UI
InfoLayer:信息UI
TipLayer:提示UI
TopLayer:頂層UI
歸屬于下一個子層級的UI窗口總是會蓋住上一個子層級的UI窗口,不管打開順序如何;而歸屬于同一個子層級的多個UI,其層級關系由打開的先后順序決定,后打開的UI總是會蓋住先打開的UI。
每兩個相連子層級之間的OrderInLayer相間1000,而相同子層級的相連窗口OrderInLayer相間10,意思是說每個子層級最多可以同時打開100個窗口;而窗口內部還可以各自劃分10個層級來使用,用于各個UI組件之間的層次關系(這些數值都可以根據具體情況調整配置)。在UGUI中,同屬于同一個OrderInLayer的UI組件也可以排布先后,這種先后關系通過Hierarchy中的上下次序來決定,所以建議優先通過這種方式來排布先后,如果不能滿足需求,再來使用不同的OrderInLayer來排布(會增加drawcall)。
有關窗口組件層級的示例代碼參考登陸界面的相關示例,代碼腳本路徑:LuaScripts/ UI/UILogin/View/UILoginView.lua。這里展示了文字特效復雜的參差關系,如果需要擴展,可參考UICanvas組件代碼。
總上所述
總的來說,這個mvc結構的UI框架是一個非常棒的ui結構,我非常的喜歡,也在我公司內部進行了推廣,大家現在都已經熟練使用了這個結構。不過最開始大家也不是很習慣,使用過程中還是碰到過很多問題的,比如:
1.大家感覺頁面拆開寫很麻煩,雖然創建了Model和Ctrl但是里面都是空的:什么事總有第一次,永遠不嘗試,你就永遠無法進步。等你寫的多了,熟練了,才能慢慢掌握mvc的精髓。
2.大家感覺Ctrl和Model中不能直接訪問View很不方便:建議大家把上面的MVC簡介再好好看看,我們既要分層也要注意解耦,如果MVC之間來回調用,會讓你的頁面耦合度增加,維護起來更麻煩。
demo示例
下面我們展示一個非常簡單的一個例子:
UILoginModel.lua
UILoginCtrl.lua
下一篇
unity如何接入puerts相關推薦