【Unity3D技巧】一个简单的Unity-UI框架的实现
如何使用
請直接導入UnityUIFramework這個UnityPackage,然后進入名為Test的Scene即可開始體驗各種特性,Enjoy!你可以通過訪問我的Github進行查閱和下載。
View,Context和UI的定義
UI是游戲中主要界面和它的子節點上的物體的統稱,如裝備列表界面中的裝備列表和每個裝備通常會被制作成兩個Prefab,這兩個Prefab被我們稱作兩個UI,這兩個UI會對應兩個UIType,在UIType里面會存儲有這個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中包含了界面中處理數據的邏輯。
Context代指游戲中每個View的上下文,存儲了這個界面的各種數據狀態,每個特定的View會持有特定的Context,游戲中會通過棧的方式管理Context。
在本框架中,會把Context和View定義在同一個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的創建和銷毀
所有界面上掛上的Mono腳本和關聯的Prefab統一以XXXView命名。
所有View的路徑統一放在UIType中進行管理,每當新創建一個View的時候,都需要在UIType中新添加一個成員變量指明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");在游戲中單獨出現的View會通過UIManager中的GetSingleUI和DestroySingleUI來進行創建和銷毀。
View的跳轉
每個View都相應擁有相應的Context來保存該界面的狀態,View的跳轉通過ContextManger管理,ContextManager中以棧的形式儲存了已經經過的界面的Context。這樣在返回的時候就可以得到需要的狀態參數。
當需要進入下一個View的時候,調用ContextManger.Instance.Push(nextContext)即可,nextContext即為下一個View需要的上下文參數, 這是會調用當前View的OnPause函數,對當前View的上下文進行存儲,并調用下一個View的OnEnter函數,對下一個Viwe的上下文進行初始化
當需要返回上一個界面的時候,調用ContextManger.Instance.Push.Pop()即可。這是會調用當前界面的OnExit函數,接著調用下一個界面的OnResume函數。
View的動畫
如果在界面上使用3D的旋轉動畫,就很難使用DoTween或者iTween在代碼里面進行動畫控制,而且為了保持戰斗模塊和UI模塊設計的一致性。因此建議使用Animator對View的各種動畫進行控制,而View的動畫一般又和View的跳轉邏輯聯系緊密,所以建議將兩者進行綁定,一個View的動畫狀態機如下圖:
一個界面在沒有顯示的時候會處于Empty狀態,當接收到OnEnter的Trigger的時候,會播放OnEnter動畫,其他的狀態如圖所示,可以參考上圖以及項目中的狀態機。不同的界面可以使用相同的狀態機,只是在某些狀態上綁定的動畫會有所不同。
這樣做的另一個好處是,我們可以使用動畫時間的方式在動畫過程中做一些回調,這樣的在界面上對回調時機進行編輯,相比使用協程或者Dotween的OnFinished函數,有更好的可編輯性。
本地化
本地化是通過單例Localization和組件LocalizedText兩個來協同實現的,不同語言的文字會存儲在Resources/Localization中的不同JSON文件中,在單例Localization中配置后語言之后,即可讀入相應的JSON文件。
每個LocalizedText所在的GameObject上都需要與Text綁定,LocalizedText會根據自己的textID對Text中的text進行本地化
分辨率適配
UGUI中的分辨率適配是通過CanvasScaler來實現的,如下圖:
在這里,我建議使用Scale With Width Or Height這種Scale模式,同時,由于大多數游戲是橫屏游戲,通過使用高度固定,寬度隨之變化的模式。這樣我們就可以以一個固定的高度進行UI設計,只需要考慮UI在水平尺度上的延伸就可以了。
提升滑動列表的性能
在UGUI中Scroller和Grid都是很好用的組件,但是由于它們在實現過程中考慮了太多對齊,排序的問題,這就導致它們在處理無限列表問題的時候遇到了極大的性能瓶頸,相關資料參考:Performance issues on android with Scrollrect。在本框架中實現的自定義組件GridScroller可以在保證可編輯性的同時,提升了滑動列表的性能。
GridScroller的原理是:在滑動到某個item上的時候,會把之前的item進行回收,并且把它放到下一個位置進行再利用。在使用GridScroller的時候,你同樣要使用ScrollRect和GridLayout,GridScroller會從這兩個組件中讀取相應的屬性并且運用到UI邏輯中。
GridScroller對外界代碼提供了一個Init的接口,通過這個接口,外界模塊可以向GridScroller傳入一個onChange回調函數,這樣在GridScroller在刷新的時候,就會動態刷新相應的itemPrefab,實現用到時再加載的特性。
[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);}對UI進行修飾
由于UGUI的Image,Text等屬性一般是不會設置Material的,我們可以通過寫腳本繼承BaseVertexEffect來對UI的Vertex進行修飾,項目中的Gradient Color和Blend Color就通過這種方式實現了顏色漸變和顏色運算的功能。通過重載ModifyVertices這個方法,你可以不實用Shader直接在腳本里對UI的渲染方式進行修飾。
轉載于:https://www.cnblogs.com/neverdie/p/unity_ui_framework.html
總結
以上是生活随笔為你收集整理的【Unity3D技巧】一个简单的Unity-UI框架的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#实现多态之一抽象
- 下一篇: UVALive 4254 Process