亲宝软件园·资讯

展开

Unity 极简UI框架

汐夜 人气:1

写ui的时候一般追求控制逻辑和显示逻辑分离,经典的类似于MVC,其余大多都是这个模式的衍生,实际上书写的时候M是在整个游戏的底层,我更倾向于将它称之为D(Data)而不是M(Model),而C(Ctrl)负责接收用户的各类UI事件,例如点击,滑动,还有其他游戏逻辑板块发过来的事件或消息,处理这些消息并更新V(View)当中的各类显示数据,这里更新数据的方式可以抽象为两种:

1.外部事件触发View更新,这时不用在意底层数据更新,因为在刷新View之前这些改变的数据可以在其他逻辑版块中直接更新完。

2.UI内部点击,滑动等事件触发View更新,这种情况下有可能需要更新底层数据,但最好不要直接修改和调用,而是选择向外部发送事件和消息的方式来告知外部需要更新数据。

无论是上面两种情况中的哪一种,都不是View直接参与外部逻辑联系,而是借助中间的Ctrl来联系,Ctrl中处理UI与外部对接的所有逻辑,并能够及时的更新View。

 

再来分析下Ctrl,我们发现Ctrl的控制流程是可以固定下来,抽象如下:

1.进入一个View界面之前,得到View组件,初始化View中各个元素的状态

2.播放一段进入动画,例如淡入

3.进入动画播放完成后,对View中的一些元素添加事件侦听,或对外部的一些事件添加侦听

4.当侦听中的事件触发后,可以选择是否对View更新,或向外部发送事件,消息

5.同样的,离开时播放一段动画,例如淡出

6.离开动画播放完成后,移除所有事件侦听,载入一个新的View或场景

 

定义Ctrl基类:

 1 using UnityEngine;
 2 using UnityEngine.Events;
 3 using UnityEngine.SceneManagement;
 4 
 5 [RequireComponent(typeof(Canvas))]
 6 public class HudBase : MonoBehaviour
 7 {
 8     public GameObject Root;
 9     protected Canvas Canvas;
10     private void Awake()
11     {
12         Canvas = GetComponent<Canvas>();
13     }
14 
15     private void Start()
16     {
17         InitState();
18         Enter(() => AddListeners());
19     }
20 
21     private void OnDestroy() => RemoveListeners();
22 
23     protected virtual void InitState() { }
24 
25     protected virtual void AddListeners() { }
26 
27     protected virtual void RemoveListeners() { }
28 
29     protected void Enter(UnityAction complete) => Canvas.FadeIn(Root, () => complete());
30 
31     protected void ExitTo(string sceneName) => Canvas.FadeOut(Root, () => SceneManager.LoadScene(sceneName));
32 
33     protected T GetViweComponent<T>() where T : HudView => GetComponent<T>();
34 
35     protected void UpdateView<T>(T t) where T : HudView => t.Refresh();
36 }

View基类:

1 using UnityEngine;
2 
3 public class HudView : MonoBehaviour
4 {
5     public virtual void Refresh() { }
6 }

View只有一个自带的更新视图的通用方法,数据来源则直接取游戏底层即可,能够从Ctrl中直接调用View视图的更新。

 

其他通用的UI方法则全部写在一个统一的地方,例如淡入淡出的函数,向外部发送事件的,侦听事件等,这里统一写成了Canvas的扩展方法,便于在基类中也方便直接调用:

 1 using System.Collections.Generic;
 2 using UnityEngine;
 3 using UnityEngine.UI;
 4 using UnityEngine.Events;
 5 using DG.Tweening;
 6 
 7 public static class HudHelper
 8 {
 9     //UI
10     public static void FadeIn(this Canvas canvas, GameObject target, TweenCallback action)
11     {
12         var cg = target.GetOrAddComponent<CanvasGroup>();
13         cg.alpha = 0;
14         cg.DOFade(1, .3f).OnComplete(action);
15     }
16 
17     public static void FadeOut(this Canvas canvas, GameObject target, TweenCallback action)
18     {
19         var cg = target.GetOrAddComponent<CanvasGroup>();
20         cg.DOFade(0, .3f).OnComplete(action);
21     }
22 
23     public static void SendEvent<T>(this Canvas canvas, T e) where T : GameEvent => EventManager.QueueEvent(e);
24 
25     public static void AddListener<T>(this Canvas canvas, EventManager.EventDelegate<T> del) where T : GameEvent => EventManager.AddListener(del);
26 
27     public static void RemoveListener<T>(this Canvas canvas, EventManager.EventDelegate<T> del) where T : GameEvent => EventManager.RemoveListener(del);
28 
29     public static void ButtonListAddListener(this Canvas canvas, List<Button> buttons, UnityAction action)
30     {
31         foreach (var bt in buttons)
32         {
33             bt.onClick.AddListener(action);
34         }
35     }
36 
37     public static void ButtonListRemoveListener(this Canvas canvas, List<Button> buttons)
38     {
39         foreach (var bt in buttons)
40         {
41             bt.onClick.RemoveAllListeners();
42         }
43     }
44 }

关于事件队列可以详细见之前的随笔:

https://www.cnblogs.com/koshio0219/p/11209191.html

具体的用法如下:(Ctrl)

 1 using UnityEngine;
 2 
 3 public class MapCanvasCtrl : HudBase
 4 {
 5     private MapCanvasView View;
 6     public GameObject UnderPanel;
 7 
 8     protected override void InitState()
 9     {
10         View = GetViweComponent<MapCanvasView>();
11         UnderPanel.SetActive(false);
12         UpdateView(View);
13     }
14 
15     protected override void AddListeners()
16     {
17         View.Back.onClick.AddListener(() => ExitTo("S_Main"));
18 
19         Canvas.ButtonListAddListener(View.TaskPoints, () =>
20         {
21             UnderPanel.SetActive(true);
22             Canvas.FadeIn(UnderPanel, () => View.HitOut.onClick.AddListener(() => ExitTo("S_DemoBattle")));
23         });
24     }
25 
26     protected override void RemoveListeners()
27     {
28         View.HitOut.onClick.RemoveAllListeners();
29         Canvas.ButtonListRemoveListener(View.TaskPoints);
30     }
31 }

只需要重写以上三个方法即可。

(View):

 1 using System.Collections.Generic;
 2 using UnityEngine.UI;
 3 using TMPro;
 4 
 5 public class MapCanvasView : HudView
 6 {
 7     public TextMeshProUGUI Resource;
 8     public TextMeshProUGUI Difficulty;
 9     public TextMeshProUGUI Reward;
10 
11     public Button HitOut;
12     public Button Back;
13 
14     public List<Button> TaskPoints = new List<Button>();
15 
16     public override void Refresh()
17     {
18         //这里更新视图
19     }
20 }

 

加载全部内容

相关教程
猜你喜欢
用户评论