Unity3D快速实现UI架构设计一
来源:互联网 发布:分视角情感分析算法 编辑:程序博客网 时间:2024/06/06 09:58
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
CSDN视频网址:http://edu.csdn.net/lecturer/144
在利用Unity3D引擎开发程序时,UI资源的加载,卸载,隐藏以及UI渐变动画等功能是UI架构设计必须考虑的。
做每一款游戏都需要将这些功能编写一遍非常耗时,在此给读者介绍一种快速的实现方式,因为我们这个是通用的
模块,所以必须要使用模板实现,而且我们的逻辑脚本是不挂接到对象上的。接下来首先设计一个管理类Manager,
代码如下所示:
using System;using System.Collections.Generic;using System.Linq;using System.Text;/// <summary>/// 抽象管理类/// </summary>/// <typeparam name="K"></typeparam>/// <typeparam name="V"></typeparam>public class Manager<T,K, V> : Singleton<T> where V : class ,IDisposable where T : Singleton<T>, new(){ protected Dictionary<K, V> mMap = new Dictionary<K, V>(); /// <summary> /// 获取 对应实体 /// </summary> /// <param name="key"></param> /// <returns></returns> public V Get(K key) { if (key == null) return null; return mMap.ContainsKey(key) ? mMap[key] : null; } /// <summary> /// 获取类型T的 Value /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public U Get<U>(K key) where U : class,V { V v = Get(key); return v as U; } /// <summary> /// 获取类型T的Value /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T Get<T>() where T : class,V { foreach(V value in mMap.Values) { if(value.GetType().Equals(typeof(T))) { return value as T; } } return null; } /// <summary> /// 添加对应实体 /// </summary> /// <param name="key"></param> /// <param name="value"></param> public bool Put(K key, V value) { if (mMap.ContainsKey(key)) { if (value == mMap[key]) { return false; } V v = mMap[key]; mMap[key] = value; v.Dispose(); } else { mMap.Add(key, value); } return true; } /// <summary> /// 删除 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Remove(K key) { if (mMap.ContainsKey(key)) { V v = mMap[key]; mMap.Remove(key); v.Dispose(); } return true; } public Dictionary<K,V>.ValueCollection Values { get { return mMap.Values; } } /// <summary> /// 清除所有管理的对象 /// </summary> public void Clear() { foreach (V value in mMap.Values) { value.Dispose(); } mMap.Clear(); }}public class ManagerT<K, V> : Manager<ManagerT<K,V>, K, V> where V : class ,IDisposable{}
在这个类属于抽象类,它利用Dictionary实现了对象的管理操作,接下来需要实现UI的管理类了,先把代码给读者展示如下:
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using UnityEngine;/// <summary>/// UI 服务类/// </summary>public class UIService : Manager<UIService, string, UIService.UI>,IDisposable{ public void Dispose() { DestroyAll(); } /// <summary> /// 创建UI /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> /// <returns></returns> private T _CreateUI<T>(string name) where T : UI { T ui = Activator.CreateInstance(typeof(T), name) as T; return ui; } public class UIHolder : MonoBehaviour { public UI ui { get; set; } } public class UI : IDisposable { public UI(string name) { _Init(name); } public enum UIStyle { Normal,//默认类型 HideByTapScene,//点击空白处隐藏类型,和黑底不冲突 } UIStyle mStyle = UIStyle.Normal; public UIStyle Style { get { return mStyle; } set { mStyle = value; } } internal GameObject mPrefab = null; protected UIPanel mPanel = null; #region 面板动画处理 protected UITweener[] mTweens = null; protected UITweener mMainTween = null; protected UITweener.ToggleStyle mMainToggleStyle = UITweener.ToggleStyle.normal; private void _TweensInit() { mTweens = mPrefab.GetComponentsInChildren<UITweener>(); if (mTweens != null) { UITweener tween; for (int i = 0; i < mTweens.Length; ++i) { tween = mTweens[i]; if (tween.toggleStyle == UITweener.ToggleStyle.OnShow) { mMainTween = tween; mMainToggleStyle = UITweener.ToggleStyle.OnShow; } if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide) { mMainTween = tween; mMainToggleStyle = UITweener.ToggleStyle.OnShowAndHide; break; } } } } private bool _HasTween() { return mMainTween != null && mMainTween.toggleStyle != UITweener.ToggleStyle.normal; } private void _TweenOnShow(EventDelegate.Callback call) { mMainTween.SetOnFinished(call); UITweener tween; for (int i = 0; i < mTweens.Length; ++i) { tween = mTweens[i]; if(tween.toggleStyle != UITweener.ToggleStyle.normal) { tween.ResetToStart(true); tween.PlayForward(); } } } private void _TweenOnHide(EventDelegate.Callback call) { if (mMainToggleStyle == UITweener.ToggleStyle.OnShow) { call(); return; } mMainTween.SetOnFinished(call); UITweener tween; for (int i = 0; i < mTweens.Length; ++i) { tween = mTweens[i]; if (tween.toggleStyle == UITweener.ToggleStyle.OnShowAndHide) { tween.ResetToStart(!true); tween.PlayReverse(); } } } private void _Dummy() { } private void _Hide() { mPrefab.SetActive(false); mHiding = false; } #endregion internal void _Init(string name) { try { GameObject prefab = Resource.LoadUI(name); mPrefab = GameObject.Instantiate(prefab) as GameObject; UIHolder uiholder = UtilGameObject.GetOrAddComponent<UIHolder>(mPrefab); uiholder.ui = this; mPrefab.name = name; mPanel = mPrefab.GetComponent<UIPanel>(); //允许Panel为空 _TweensInit(); } catch (Exception e) { Looper.LogException(e); } UIService.Instance.InitUI(mPrefab); UIService.Instance._OnShowUI(this, true); } #region <默认属性> /// <summary> /// 深度信息 /// </summary> public int depth { get { if (mPanel==null) { return -1; } return mPanel.depth; } set { if (mPanel == null) return; mPanel.depth = value; } } /// <summary> /// 是否正在显示 /// </summary> /// <returns></returns> public bool IsShowing() { if (mPrefab == null) return false; return mPrefab.activeSelf; } float mLastShowTime = Time.time; /// <summary> /// 最后一次显示的时间 /// </summary> public float LastShowTime { get { return mLastShowTime; } set { mLastShowTime = value; } } #endregion /// <summary> /// 名字(和预制件名称一样) /// </summary> public string Name { get { return mPrefab != null ? mPrefab.name : ""; } } /// <summary> /// 销毁对象 /// </summary> public void Dispose() { UIService.Instance._OnHidUI(this); try { OnClose(); if (mPrefab != null) { GameObject.DestroyImmediate(mPrefab); mPrefab = null; } } catch (Exception e) { Looper.LogException(e); } } /// <summary> /// 刷新界面 /// 1 Grid 重排问题 /// </summary> public void Refresh() { UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>(); foreach (UIGrid grid in grids) { if (grid != null && !grid.animateSmoothly) { grid.Reposition(); } } } public IEnumerator _Refresh() { { UIGrid[] grids = mPrefab.GetComponentsInChildren<UIGrid>(); foreach (UIGrid grid in grids) { if (grid != null && !grid.enabled) { grid.repositionNow = true; grid.Reposition(); } } } yield return null; } //解决同一个UI动画隐藏还没结束,动画显示就开始了 状态不对的问题 bool mHiding = false; /// <summary> /// 是否显示 /// </summary> public void Show(bool v) { if (v) { if (mHiding) { _Hide(); } UIService.Instance._OnShowUI(this); } else { UIService.Instance._OnHidUI(this); } try { if (mPrefab != null) { if (_HasTween()) { if (v) { mPrefab.SetActive(true); _TweenOnShow(_Dummy); } else { mHiding = true; _TweenOnHide(_Hide); } } else { mPrefab.SetActive(v); } OnShow(v); if (v) { LastShowTime = Time.time; Refresh(); //(); } } } catch (Exception e) { Looper.LogException(e); } } /// <summary> /// 跟随场景中物体 /// </summary> /// <param name="target"></param> public void ApplyHub(Transform target) { NGUIExt guiExt = PluginManager.Instance.Get<NGUIExt>(); if (guiExt != null) { guiExt.ApplyHud(mPrefab, target); } } public virtual void OnCreate() { } public virtual void OnShow(bool v) { } public virtual void OnClose() { } /// <summary> /// 点击事件 /// </summary> /// <param name="obj">被点击的控件</param> public virtual void OnClick(GameObject obj) { } /// <summary> /// 双击事件 /// </summary> /// <param name="obj">被双击的控件</param> public virtual void OnDoubleClick(GameObject obj) { } /// <summary> /// 按住事件 /// </summary> /// <param name="obj">被Pressed的控件</param> /// <param name="pressed"></param> public virtual void OnPress(GameObject obj, bool isPressed) { } /// <summary> /// 拖动事件 /// </summary> /// <param name="obj">拖动的控件</param> /// <param name="delta"></param> public virtual void OnDrag(GameObject obj, Vector2 delta) { } /// <summary> /// 拖放事件 /// </summary> /// <param name="obj">拖放的当前控件</param> /// <param name="objSelected">一直被拖住的控件</param> public virtual void OnDrap(GameObject obj, GameObject objSelected) { } /// <summary> /// 显示Tooltip事件 /// </summary> /// <param name="obj"></param> /// <param name="isShow">显示或隐藏Tooltip</param> public virtual void OnTooltip(GameObject obj, bool isShow) { } /// <summary> /// 被选中事件 /// </summary> /// <param name="obj">被选中的控件</param> /// <param name="isSelected">选中或取消被选中</param> public virtual void OnSelect(GameObject obj, bool isSelected) { } /// <summary> /// 光标划过事件 /// </summary> /// <param name="obj"></param> /// <param name="isHover">光标进入或光标离开</param> public virtual void OnHover(GameObject obj, bool isHover) { } /// <summary> /// 根据类型获取对应名称控件; /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> /// <returns></returns> protected T GetChild<T>(string name,GameObject obj = null, int index = 0) where T : MonoBehaviour { if(obj == null) { obj = mPrefab; } Transform child = obj.transform.Find(name); if (child == null) { T[] childs = obj.GetComponentsInChildren<T>(); foreach (T t in childs) { if (t.gameObject.name == name) { return t; } } } else { if (child.childCount == 0) { return child.GetComponent<T>(); } { int count = 0; T[] comps = child.GetComponents<T>(); foreach (T t in comps) { if (t.gameObject.name == name && count == index) { return t; } count++; } } { int count = 0; T[] childs = child.GetComponentsInChildren<T>(); foreach (T t in childs) { if (t.gameObject.name == name && count == index) { return t; } count++; } } } Debug.LogError(obj.name + " hasn't Components :" + typeof(T).Name + " in children named:" + name); return null; } protected GameObject FindChild(string name) { var child = mPrefab.transform.FindChild(name); return child.gameObject; } protected T FindChild<T>(string name) where T : Component { var child = mPrefab.transform.FindChild(name); T cmp = child.GetComponent<T>(); return cmp; } /// <summary> /// 获取对应名称子控件; /// </summary> /// <param name="name"></param> /// <returns></returns> protected GameObject GetChild(string name, GameObject obj = null) { if(obj == null) { obj = mPrefab; } Transform child = obj.transform.Find(name); if (child == null) { Debug.LogError(obj.name + "is not find child of:" + name); return null; } return child.gameObject; } /// <summary> /// 用指定的对象替换子对象 /// </summary> /// <param name="name">子对象名字</param> /// <param name="obj">指定的对象</param> /// <returns></returns> protected bool ReplaceChild(string name, GameObject obj) { GameObject orginal = GetChild(name); if (orginal == null) {GameObject.DestroyImmediate (obj);return false;} obj.transform.parent = orginal.transform.parent; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one;obj.name = orginal.name;orginal.transform.parent = null;GameObject.DestroyImmediate (orginal); return true; } /// <summary> /// 用指定的对象替换子对象 /// </summary> /// <param name="orginal">原件</param> /// <param name="obj">指定的对象</param> /// <returns></returns> protected bool ReplaceChild(GameObject orginal, GameObject obj) { if (orginal == null) {GameObject.DestroyImmediate (obj);return false;} obj.transform.parent = orginal.transform.parent; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one;obj.name = orginal.name;orginal.transform.parent = null;GameObject.DestroyImmediate (orginal); return true; } } NGUIExt mPlugin; GameObject mBG; UIPanel mBGPanel; int mBGCount = 0; private void _OnShowUI(UI t,bool init = false) { if (t.IsShowing()) { if(!init) return; } if (t.IsShowBlackBG()) { mBGCount++; if (mBGCount > 0 && mBG.activeSelf == false) { mBG.SetActive(true); } if (mBG.activeSelf) { mBGPanel.depth = t.depth-1; } } } private void _OnHidUI(UI t) { if (!t.IsShowing()) return; if (t.IsShowing() && t.IsShowBlackBG()) { mBGCount--; if(mBGCount <= 0) { mBGCount = 0; if (mBG.activeSelf == true) { mBG.SetActive(false); } } if (mBG.activeSelf) { UI ui = _GetLastShowUI(true, t); if (ui != null) mBGPanel.depth = ui.depth-1; } } } public bool IsFingerHoverGUI() { if(mPlugin == null) { return false; } return mPlugin.IsFingerHoverGUI; } public bool IsFingerHoverGUI3D() { if (mPlugin == null) { return false; } return mPlugin.IsFingerHoverGUI3D(); } public bool IsFingerHoverGUIWithout3D() { if (mPlugin == null) { return false; } return mPlugin.IsFingerHoverGUIWithout3D(); } public bool IsPrefab(GameObject ui_prefab) { return mPlugin.IsPrefab(ui_prefab); } /// <summary> /// 初始化 继承与 Singleton 对象构建的时候被调用 /// </summary> protected override void OnCreate() { mPlugin = PluginManager.Instance.Get<NGUIExt>(); if (mPlugin != null) { mPlugin.SetEventHandler(this._HandlerUIEvent); } GameObject prefab = Resource.LoadUICommon("black_background"); Looper.Assert(prefab != null , "默认黑底 black_background Prefab不存在 !!"); if(prefab != null) { mBG = mPlugin.AddChild(prefab); mBGPanel = mBG.GetComponent<UIPanel>(); mBG.transform.localScale = new Vector3(1, 1, 1); mBG.transform.localPosition = new Vector3(mBG.transform.localPosition.x, mBG.transform.localPosition.y, Mathf.Clamp(mBG.transform.localPosition.z, -2f, 2f)); if(mBG != null) { UISprite sprite = mBG.GetComponent<UISprite>(); BoxCollider collider = mBG.GetComponent<BoxCollider>(); if(sprite!= null) { Vector2 size = mPlugin.GetSize(); sprite.SetDimensions((int)size.x, (int)size.y); collider.size = new Vector3(size.x, size.y, 0); } } mBG.SetActive(false); } //EasyTouch.On_SimpleTap += On_SimpleTap; } public void InitUI(GameObject ui) { try { LayerUtils.SetLayer(ui.transform, (int)LayerUtils.ELayerIndex.ui); ui.transform.parent = mPlugin.GetRoot().transform; switch(ui.name) { default: ui.transform.localScale = new Vector3(1, 1, 1); ui.transform.localPosition = Vector3.zero; break; } } catch (Exception e) { Looper.LogException(e); } } /// <summary> /// 创建UI /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> /// <returns></returns> public T CreateUI<T>(string name) where T: UI { UI t = this.Get(name) as T; if(t == null) { t = _CreateUI<T>(name) as UI; try { t.OnCreate(); } catch (Exception e) { Looper.LogException(e); } Put(name, t); } return t as T; } List<UI> mUIScene = new List<UI>(); /// <summary> /// 创建一个不加入管理队列的UI,主要用于世界地图上关卡界面的创建。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> /// <returns></returns> public T CreateUIWithoutManager<T>(string name) where T : UI { T ui = _CreateUI<T>(name); try { ui.OnCreate(); } catch (Exception e) { Looper.LogException(e); } mUIScene.Add(ui); return ui; } /// <summary> /// 销毁不加入队列的UI /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ui"></param> public void CloseUIWithoutManager<T>(T ui) where T : UI { try { ui.OnClose(); ui.Dispose(); } catch (Exception e) { Looper.LogException(e); } mUIScene.Remove(ui); } /// <summary> /// 显示UI /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> public T ShowUI<T>(string name) where T : UI { T t = CreateUI<T>(name); if(t != null) { t.Show(true); } return t; } /// <summary> /// 显示UI /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name"></param> public T HideUI<T>(string name) where T : UI { T t = Get<T>(name); if (t != null) { t.Show(!true); } return t; } Stack<UI> mStack = new Stack<UI>(); /// <summary> /// 清除栈 /// </summary> public void StackClean() { mStack.Clear(); } /// <summary> /// UI隐藏压栈 /// </summary> /// <param name="t"></param> /// <returns></returns> public UI Push(UI t) { if (t != null) { t.Show(false); mStack.Push(t); } return t; } /// <summary> /// UI隐藏压栈 /// </summary> /// <param name="t"></param> /// <returns></returns> public T Push<T>(string name) where T: UI { T t = Get<T>(name); if (t != null) { t.Show(false); mStack.Push(t); } return t; } /// <summary> /// UI显示出栈 /// </summary> /// <param name="t"></param> /// <returns></returns> public UI Pop() { UI t = mStack.Pop(); if (t != null) { t.Show(true); } return t; } /// <summary> /// 销毁UI /// </summary> /// <param name="name"></param> public void Distroy(string name) { UI ui = Get(name); if(ui != null) { ui.Dispose(); Remove(name); } } public void Distroy<T>(string name) where T : UI { UI ui = Get<T>(name); if (ui != null) { ui.Dispose(); Remove(name); } } public void DestroyAll(bool includeScene= false) { StackClean(); Clear(); if(includeScene) { foreach (UI ui in mUIScene) { ui.Dispose(); } mUIScene.Clear(); } } /// <summary> /// 隐藏其他UI /// </summary> /// <param name="name"></param> public void HideOtherUI(string name) { foreach (UI ui in Values) { if (ui.Name.Equals(name)) continue; ui.Show(false); } } UI _GetLastShowUI(bool showBG = false,UI except=null) { UI lastShowUI = null; float lastShowTime = 0; foreach (UI ui in Values) { if (ui == except) continue; if (ui.IsShowing() && ui.LastShowTime > lastShowTime) { if (showBG) { if (ui.IsShowBlackBG()) { lastShowUI = ui; lastShowTime = ui.LastShowTime; } }else { lastShowUI = ui; lastShowTime = ui.LastShowTime; } } } return lastShowUI; } /// <summary> /// 隐藏最新显示的UI /// </summary> public void HideLastShow() { UI lastShowUI = _GetLastShowUI(); if (lastShowUI != null) { lastShowUI.Show(false); } } /// <summary> /// 隐藏所有UI /// </summary> public void HideAllUI() { foreach(UI ui in Values) { if(ui != null)ui.Show(false); } } /// <summary> /// 获取UI跟面板 /// </summary> /// <param name="obj"></param> /// <returns></returns> GameObject _GetRootPanelExt(GameObject obj) { Transform parent = obj.transform.parent; UIHolder uiHolder = null;// = root.GetComponent<UIService.UIHolder>(); while (parent != null) { if (parent.gameObject.GetComponent<UICamera>() != null) break; UIHolder tempPanel = parent.GetComponent<UIHolder>(); if (tempPanel != null) { uiHolder = tempPanel; } parent = parent.parent; } if (uiHolder == null) { return null; } return uiHolder.gameObject; } /// <summary> /// NGUI事件处理器 /// </summary> /// <param name="eventNane">事件名称</param> /// <param name="sender">发送事件的控件</param> /// <param name="arg">事件参数</param> private void _HandlerUIEvent(string eventName, GameObject sender, object arg) { try { if(sender == mBG) { //MainLooper.LogError("mBG, eventName:" + eventName + "!!"); if (eventName.Equals("OnClick")) { } return; } GameObject root = _GetRootPanelExt(sender);//mPlugin.GetRootPanel(sender); if (root == null) return; UI ui = Get(root.name); if(ui == null) { UIHolder uiHolder = root.GetComponent<UIHolder>(); if( uiHolder!= null) ui = uiHolder.ui; } if (ui == null) { Debug.LogWarning("UI:" + root.name + " not match prefab's name " + sender.name); return; } if (eventName.Equals("OnClick")) { ui.OnClick(sender); } else if (eventName.Equals("OnPress")) { ui.OnPress(sender, (bool)arg); } else if (eventName.Equals("OnDrag")) { ui.OnDrag(sender, (Vector2)arg); } else if (eventName.Equals("OnDrop")) { ui.OnDrap(sender, (GameObject)arg); } else if (eventName.Equals("OnSelect")) { ui.OnSelect(sender, (bool)arg); } else if (eventName.Equals("OnHover")) { ui.OnHover(sender, (bool)arg); } else if (eventName.Equals("OnTooltip")) { ui.OnTooltip(sender, (bool)arg); } else if (eventName.Equals("OnDoubleClick")) { ui.OnDoubleClick(sender); } } catch(Exception e) { Looper.LogException(e); } }}
该类实现了UI的创建,也就是我们说的实例化操作,以及UI的显示,隐藏,动画等效果。在代码的最后使用了点击的回调函数避免
将脚本挂接到对象上。以上类的实现基本上把UI的大部分功能都实现出来了,可以直接拿过来使用。
0 0
- Unity3D快速实现UI架构设计一
- Unity3D快速实现UI架构设计二
- Unity3d UI设计简述
- Unity3D之UI设计
- 游戏UI框架设计(一) : 架构设计理论篇
- Unity3D问题之简单UI框架设计和实现
- Unity3D架构系列之-FSM有限状态机设计(一)
- Unity3D架构系列之- FSM有限状态机设计一
- Unity3D架构系列之- FSM有限状态机设计一
- Unity3D游戏架构设计之对象管理【一】
- iOS UI架构设计
- Unity3D研究:Unity3D引擎架构设计
- Unity3D研究:Unity3D引擎架构设计
- Unity3D研究:Unity3D引擎架构设计
- Unity3D研究:Unity3D引擎架构设计
- Unity3D架构设计NavMesh寻路
- Unity3D架构设计NavMesh寻路
- unity3d 快速拼ui工具 psd2ugui
- 关于调用TerminateProcess关闭其他进程的权限问题
- HTML与body标签的一些研究
- 24. Swap Nodes in Pairs using recursion
- JSR330注解和Spring注解对比
- 开源DBCP、C3P0、Proxool 、 BoneCP连接池的比较
- Unity3D快速实现UI架构设计一
- Android Architecture Blueprints(架构蓝图)
- R语言数据可视化之图形参数修改
- 第一章 绪论
- 20170514_单链表的构造与逆置
- SpringMVC 使用JSR-303进行校验 @Valid
- [PAT-乙级]1014.福尔摩斯的约会
- shell 练习题 1-10
- MainActivity——接上文网路请求