程序语言:C#
开发平台:Visual Studio 2019
游戏引擎:Unity
版本:2019.4.6f1 【2017版本以上均可】
答:UI设计(或称界面设计)是指对软件的人机交互、操作逻辑、界面美观的整体设计。
UI交互行为作为重要的环节,常以多样化操作提高用户交互体验,而如何选择响应方式,如按下时反馈、松手时反馈等,需要开发者手动调整。因而便利化代码操作以更灵活处理多种交互行为:
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI.Framework
{
public delegate void PointerHandler(PointerEventData data);
///
/// UI 事件监听器
///
public class UIEventListener : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
public event PointerHandler Click;
public event PointerHandler Enter;
public event PointerHandler Exit;
public event PointerHandler Down;
public event PointerHandler Up;
///
/// 点击
///
///
public void OnPointerClick(PointerEventData eventData)
{
Click?.Invoke(eventData);
}
///
/// 点下
///
///
public void OnPointerDown(PointerEventData eventData)
{
Down?.Invoke(eventData);
}
///
/// 进入
///
///
public void OnPointerEnter(PointerEventData eventData)
{
Enter?.Invoke(eventData);
}
///
/// 离开
///
///
public void OnPointerExit(PointerEventData eventData)
{
Exit?.Invoke(eventData);
}
///
/// 松键
///
///
public void OnPointerUp(PointerEventData eventData)
{
Up?.Invoke(eventData);
}
}
}`
using UnityEngine;
using UnityEngine.EventSystems;
UnityEngine
:Unity提供的扩展程序,此处引用为继承MonoBehaviour
允许挂载到场景物体上UnityEngine.EventSystem
:Unity事件系统,此处为实现其提供的多种交互接口,以灵活化交互方式的使用public event PointerHandler Click;
public event PointerHandler Enter;
public event PointerHandler Exit;
public event PointerHandler Down;
public event PointerHandler Up;
event
:使用接口实现操作方法,如下为使用点击事件接口实现点击事件行为。
public void OnPointerClick(PointerEventData eventData)
{
Click?.Invoke(eventData);
}
OnPointerClick()
:由IPointClickHandler
提供的实现方法,指点击行为的方法均为此Click
:指点击行为事件Click?.Invoke(eventData)
:判断当前点击行为,如果是执行点击的对应事件
挂载于UI窗口。用于提供给UI窗口的显隐方式,如[立即显隐],[延迟显隐],[渐变显隐]等。
using System.Collections;
using UnityEngine;
using Tool;
namespace UI.Framework
{
///
/// UI 窗口显隐效果【挂载于指定显隐窗口上】
///
[RequireComponent(typeof(CanvasGroup))]
public class UIWindow : MonoBehaviour
{
//CanvasGroup提供透明度更变显隐(性能上最优)
private CanvasGroup group;
protected void Awake()
{
group = GetComponent<CanvasGroup>();
}
//立即显隐
private void SetVisibleInstantly(bool state)
{
group.alpha = state ? 1 : 0;
group.blocksRaycasts = state;
}
///
/// 设置可见性
///
/// 是否可见
/// 延迟时间,默认为0
public void SetVisible(bool state, float delay = 0)
{
StartCoroutine(SetVisibleDelay(state, delay));
}
///
/// 延时显隐
///
/// 是否可见
/// 延迟时间
///
private IEnumerator SetVisibleDelay(bool state, float delay)
{
yield return new WaitForSeconds(delay);
SetVisibleInstantly(state);
}
///
/// 获取监听器
///
///
///
public UIEventListener GetListener(string childName)
{
Transform childTF = transform.FindChildTF(childName);
if (childTF == null) return null;
UIEventListener listener = childTF.GetComponent<UIEventListener>();
if (listener == null) listener = childTF.gameObject.AddComponent<UIEventListener>();
return listener;
}
}
}
using System.Collections;
using UnityEngine;
using Tool;
System.Colletion
:Biu La Biu La~UnityEngine
:同3.1描述Tool
:第三方工具,由作者自己准备的工具包,后续会说及此工具包内容[RequireComponent(typeof(CanvasGroup))]
CanvaGroup
组件[AddComponent(typeof(CanvasGroup))]
,当物体没有该组件直接添加该组件private CanvasGroup group;
CanvasGroup
组件改变 0~1 透明度来实现UI的隐藏。CanvasGroup
组件仅从更变显隐状态上比SetActive()
的性能开支更优。protected void Awake()
{
group = GetComponent<CanvasGroup>();
}
private void SetVisibleInstantly(bool state)
{
group.alpha = state ? 1 : 0;
group.blocksRaycasts = state;
}
SetVisibleInstantly()
:即时显隐,我们通过改变画布的alpha透明度实现这以行为。blockRagtCastes
:决定该CanvasGroup
组件是否接口射线检测Click
等行为private IEnumerator SetVisibleDelay(bool state, float delay)
{
yield return new WaitForSeconds(delay);
SetVisibleInstantly(state);
}
IEnumerator
:协程,允许程序暂缓一时间后执行。SetVisibleInstantly()
方法public void SetVisible(bool state, float delay = 0)
{
StartCoroutine(SetVisibleDelay(state, delay));
}
SetVisible()
:封装 直接显隐 与 延时显隐 的方法public UIEventListener GetListener(string childName)
{
Transform childTF = transform.FindChildTF(childName);
if (childTF == null) return null;
UIEventListener listener = childTF.GetComponent<UIEventListener>();
if (listener == null) listener = childTF.gameObject.AddComponent<UIEventListener>();
return listener;
}
UIController
的消息通知,来进一步实现要求的显隐方法。transfrom.FindChild()
:来自于using Tool
(自己准备的工具类命名空间)。其目的是查询当前脚本上挂载的物体上的 事件监听组件。childTF == null
:说明场景内并无命名 childName参数 的UI对象。Debug
告诉我们并无此对象。listener == null
:即查找到的UI对象上,发现脚没有 事件监听组件。给它添加一个就完事了。return listener
:我们最终只为获取 事件监听组件对象,返回它。用于管理所有UI状态的综合管理器,主要用于控制进入游戏后呈现的UI状态。即隐藏主菜单外的所有UI界面。
using System.Collections.Generic;
using Tool;
using UnityEngine;
namespace UI.Framework
{
///
/// UI 管理器
///
public class UIManager : GetInstance<UIManager>
{
// 例如:游戏一开始隐藏所有UI
private Dictionary<string, UIWindow> cache;
///
/// 保护级 防父类覆盖
///
protected override void Init()
{
base.Init();
cache = new Dictionary<string, UIWindow>();
//查询 UIWindow组件 的物体
UIWindow[] ui = FindObjectsOfType<UIWindow>();
//设置 隐藏
for (int i = 0; i < ui.Length; i++)
{
ui[i].SetVisible(false);
cache.Add(ui[i].GetType().Name, ui[i]);
}
}
///
/// 获取某一窗口
///
///
///
public T GetWindow<T>() where T:UIWindow
{
string key = typeof(T).Name;
return cache[key] as T;
}
}
}
using System.Collections.Generic;
using Tool;
using UnityEngine;
public class UIManager : GetInstance<UIManager>
GetInstance
:为笔者命名的单例模式,命名随意。Singleton
,继承MonoBehaviour
的单例命名为MonoSingleton
MonoSingleton
,以便在Unity游戏中运行时被使用。private Dictionary<string, UIWindow> cache;
UIWindow
对象的映射关系,为后续调用从中索引即可。protected override void Init()
{
cache = new Dictionary<string, UIWindow>();
//查询 UIWindow组件 的物体
UIWindow[] ui = FindObjectsOfType<UIWindow>();
//设置 隐藏
for (int i = 0; i < ui.Length; i++)
{
ui[i].SetVisible(false);
cache.Add(ui[i].GetType().Name, ui[i]);
}
}
Init()
:GetInstance
单例中准备的初始化方法。此为覆写单例中的Init()
方法。protected
:保护级,只允许父类即其子类可访问。cache
分配了空间用于存储索引的UIWindow
组件以及其挂载的物体名称信息。后续对某一UI对象的显隐行为通过其命名索引UIWindow
组件,调用其内方法做下铺垫。SetVisible()
使UI对象的默认状态为 隐藏。public T GetWindow<T>() where T:UIWindow
{
string key = typeof(T).Name;
return cache[key] as T;
}
T
:泛型where T:Window
:指定这个类型为UIWindow
UIWindow
对象的命名,在存储的cache
表中索引该UIWindow
。这样我们可以直接通过命名获取其挂载的UIWindow
对象,进一步使用其方法。这一体现在UIController
。
用于实现各UI界面交互行为逻辑的实现,具体有[立即显隐]、[延时显隐]、[渐变显隐]等
using Tool;
using UI.Achieve;
using UI.Framework;
using UnityEngine;
namespace UI.Framework
{
public class UIController : GetInstance<UIController>
{
//管理UI界面
private void Start()
{
UIManager.Instance.GetWindow<MainButton>().SetVisible(true);
}
//寻找战局
public void FindRound()
{
UIManager.Instance.GetWindow<FindParty>().SetVisible(true);
}
//创建战局
public void CreateRound()
{
UIManager.Instance.GetWindow<CreateParty>().SetVisible(true);
}
//设置
public void Setting()
{
UIManager.Instance.GetWindow<Set>().SetVisible(true);
}
//仓库
public void WareHouse()
{
UIManager.Instance.GetWindow<Warehouse>().SetVisible(true);
}
//关于我们
public void AboutUs()
{
UIManager.Instance.GetWindow<AboutUs>().SetVisible(true);
}
//返回主窗口
public void Back()
{
UIManager.Instance.GetWindow<MainButton>().SetVisible(true);
}
}
}
using Tool;
using UI.Achieve;
using UI.Framework;
using UnityEngine;
using UI.Framework
:上面的脚本内容均在 UI.Framework下存储,同一命名空间下可直接引用。using UIAchieve
:UI的实现对象,如我们在Canvas上创建了一个管理所有行为的脚本,这里并未用到。UIController
不同,它们的目的是对所有交互行为的封装,通过一个对象实现对所有UI的控制的控制器,如同一个遥控器,具体我们想要遥控器去干什么,怎么干,是Achieve的事情。private void Start()
{
UIManager.Instance.GetWindow<MainButton>().SetVisible(true);
}
UIManager
中我们默认所有窗口隐藏,我们想要游戏一开始就显示该对象public void FindRound()
{
UIManager.Instance.GetWindow<FindParty>().SetVisible(true);
}
UIManager.Instance.GetWindow().SetVisible(true)
来直接使用。using UI.Acheive
类中实现具体行为如显示后获取玩家数据等,直接使用方法。获取数据还需另行操作。