【Unity3D技巧】一个简单的Unity-UI框架的实现
如何使用
請(qǐng)直接導(dǎo)入U(xiǎn)nityUIFramework這個(gè)UnityPackage,然后進(jìn)入名為Test的Scene即可開始體驗(yàn)各種特性,Enjoy!你可以通過(guò)訪問(wèn)我的Github進(jìn)行查閱和下載。
View,Context和UI的定義
UI是游戲中主要界面和它的子節(jié)點(diǎn)上的物體的統(tǒng)稱,如裝備列表界面中的裝備列表和每個(gè)裝備通常會(huì)被制作成兩個(gè)Prefab,這兩個(gè)Prefab被我們稱作兩個(gè)UI,這兩個(gè)UI會(huì)對(duì)應(yīng)兩個(gè)UIType,在UIType里面會(huì)存儲(chǔ)有這個(gè)UI全局唯一的名字和路徑,如下:
public class UIType {public string Path { get; private set; }public string Name { get; private set; }public UIType(string path){Path = path;Name = path.Substring(path.LastIndexOf('/') + 1);}public override string ToString(){return string.Format("path : {0} name : {1}", Path, Name);} }View代指游戲中的主要界面,例如:主界面,裝備界面,裝備詳情界面等等。在View中包含了界面中處理數(shù)據(jù)的邏輯。
Context代指游戲中每個(gè)View的上下文,存儲(chǔ)了這個(gè)界面的各種數(shù)據(jù)狀態(tài),每個(gè)特定的View會(huì)持有特定的Context,游戲中會(huì)通過(guò)棧的方式管理Context。
在本框架中,會(huì)把Context和View定義在同一個(gè)cs文件中,如下:
public class OptionMenuContext :BaseContext{public OptionMenuContext() : base(UIType.OptionMenu){}}public class OptionMenuView : AnimateView{public override void OnEnter(BaseContext context)public override void OnExit(BaseContext context)public override void OnPause(BaseContext context)public override void OnResume(BaseContext context)}View的創(chuàng)建和銷毀
所有界面上掛上的Mono腳本和關(guān)聯(lián)的Prefab統(tǒng)一以XXXView命名。
所有View的路徑統(tǒng)一放在UIType中進(jìn)行管理,每當(dāng)新創(chuàng)建一個(gè)View的時(shí)候,都需要在UIType中新添加一個(gè)成員變量指明View的路徑。
public static readonly UIType MainMenu = new UIType("View/MainMenuView"); public static readonly UIType OptionMenu = new UIType("View/OptionMenuView"); public static readonly UIType NextMenu = new UIType("View/NextMenuView"); public static readonly UIType HighScore = new UIType("View/HighScoreView");在游戲中單獨(dú)出現(xiàn)的View會(huì)通過(guò)UIManager中的GetSingleUI和DestroySingleUI來(lái)進(jìn)行創(chuàng)建和銷毀。
View的跳轉(zhuǎn)
每個(gè)View都相應(yīng)擁有相應(yīng)的Context來(lái)保存該界面的狀態(tài),View的跳轉(zhuǎn)通過(guò)ContextManger管理,ContextManager中以棧的形式儲(chǔ)存了已經(jīng)經(jīng)過(guò)的界面的Context。這樣在返回的時(shí)候就可以得到需要的狀態(tài)參數(shù)。
當(dāng)需要進(jìn)入下一個(gè)View的時(shí)候,調(diào)用ContextManger.Instance.Push(nextContext)即可,nextContext即為下一個(gè)View需要的上下文參數(shù), 這是會(huì)調(diào)用當(dāng)前View的OnPause函數(shù),對(duì)當(dāng)前View的上下文進(jìn)行存儲(chǔ),并調(diào)用下一個(gè)View的OnEnter函數(shù),對(duì)下一個(gè)Viwe的上下文進(jìn)行初始化
當(dāng)需要返回上一個(gè)界面的時(shí)候,調(diào)用ContextManger.Instance.Push.Pop()即可。這是會(huì)調(diào)用當(dāng)前界面的OnExit函數(shù),接著調(diào)用下一個(gè)界面的OnResume函數(shù)。
View的動(dòng)畫
如果在界面上使用3D的旋轉(zhuǎn)動(dòng)畫,就很難使用DoTween或者iTween在代碼里面進(jìn)行動(dòng)畫控制,而且為了保持戰(zhàn)斗模塊和UI模塊設(shè)計(jì)的一致性。因此建議使用Animator對(duì)View的各種動(dòng)畫進(jìn)行控制,而View的動(dòng)畫一般又和View的跳轉(zhuǎn)邏輯聯(lián)系緊密,所以建議將兩者進(jìn)行綁定,一個(gè)View的動(dòng)畫狀態(tài)機(jī)如下圖:
一個(gè)界面在沒有顯示的時(shí)候會(huì)處于Empty狀態(tài),當(dāng)接收到OnEnter的Trigger的時(shí)候,會(huì)播放OnEnter動(dòng)畫,其他的狀態(tài)如圖所示,可以參考上圖以及項(xiàng)目中的狀態(tài)機(jī)。不同的界面可以使用相同的狀態(tài)機(jī),只是在某些狀態(tài)上綁定的動(dòng)畫會(huì)有所不同。
這樣做的另一個(gè)好處是,我們可以使用動(dòng)畫時(shí)間的方式在動(dòng)畫過(guò)程中做一些回調(diào),這樣的在界面上對(duì)回調(diào)時(shí)機(jī)進(jìn)行編輯,相比使用協(xié)程或者Dotween的OnFinished函數(shù),有更好的可編輯性。
本地化
本地化是通過(guò)單例Localization和組件LocalizedText兩個(gè)來(lái)協(xié)同實(shí)現(xiàn)的,不同語(yǔ)言的文字會(huì)存儲(chǔ)在Resources/Localization中的不同JSON文件中,在單例Localization中配置后語(yǔ)言之后,即可讀入相應(yīng)的JSON文件。
每個(gè)LocalizedText所在的GameObject上都需要與Text綁定,LocalizedText會(huì)根據(jù)自己的textID對(duì)Text中的text進(jìn)行本地化
分辨率適配
UGUI中的分辨率適配是通過(guò)CanvasScaler來(lái)實(shí)現(xiàn)的,如下圖:
在這里,我建議使用Scale With Width Or Height這種Scale模式,同時(shí),由于大多數(shù)游戲是橫屏游戲,通過(guò)使用高度固定,寬度隨之變化的模式。這樣我們就可以以一個(gè)固定的高度進(jìn)行UI設(shè)計(jì),只需要考慮UI在水平尺度上的延伸就可以了。
提升滑動(dòng)列表的性能
在UGUI中Scroller和Grid都是很好用的組件,但是由于它們?cè)趯?shí)現(xiàn)過(guò)程中考慮了太多對(duì)齊,排序的問(wèn)題,這就導(dǎo)致它們?cè)谔幚頍o(wú)限列表問(wèn)題的時(shí)候遇到了極大的性能瓶頸,相關(guān)資料參考:Performance issues on android with Scrollrect。在本框架中實(shí)現(xiàn)的自定義組件GridScroller可以在保證可編輯性的同時(shí),提升了滑動(dòng)列表的性能。
GridScroller的原理是:在滑動(dòng)到某個(gè)item上的時(shí)候,會(huì)把之前的item進(jìn)行回收,并且把它放到下一個(gè)位置進(jìn)行再利用。在使用GridScroller的時(shí)候,你同樣要使用ScrollRect和GridLayout,GridScroller會(huì)從這兩個(gè)組件中讀取相應(yīng)的屬性并且運(yùn)用到UI邏輯中。
GridScroller對(duì)外界代碼提供了一個(gè)Init的接口,通過(guò)這個(gè)接口,外界模塊可以向GridScroller傳入一個(gè)onChange回調(diào)函數(shù),這樣在GridScroller在刷新的時(shí)候,就會(huì)動(dòng)態(tài)刷新相應(yīng)的itemPrefab,實(shí)現(xiàn)用到時(shí)再加載的特性。
[RequireComponent(typeof(ScrollRect))] public class GridScroller : MonoBehaviour {// public UI elements //[SerializeField]private Transform _itemPrefab;[SerializeField]private GridLayoutGroup _grid;// public fields //[SerializeField]private Movement _moveType = Movement.Horizontal;public delegate void OnChange(Transform trans, int index);public void Init(OnChange onChange, int itemCount, Vector2? normalizedPosition = null){Clear();InitScroller();InitGrid();InitChildren(onChange, itemCount);InitTransform(normalizedPosition);}對(duì)UI進(jìn)行修飾
由于UGUI的Image,Text等屬性一般是不會(huì)設(shè)置Material的,我們可以通過(guò)寫腳本繼承BaseVertexEffect來(lái)對(duì)UI的Vertex進(jìn)行修飾,項(xiàng)目中的Gradient Color和Blend Color就通過(guò)這種方式實(shí)現(xiàn)了顏色漸變和顏色運(yùn)算的功能。通過(guò)重載ModifyVertices這個(gè)方法,你可以不實(shí)用Shader直接在腳本里對(duì)UI的渲染方式進(jìn)行修飾。
轉(zhuǎn)載于:https://www.cnblogs.com/neverdie/p/unity_ui_framework.html
總結(jié)
以上是生活随笔為你收集整理的【Unity3D技巧】一个简单的Unity-UI框架的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C#实现多态之一抽象
- 下一篇: UVALive 4254 Process