2017-05-14 20:14:32 jxw167 阅读数 2720
  • Unity3DUI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    984 人正在学习 去看看 伍晓波

笔者介绍:姜雪伟,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的大部分功能都实现出来了,可以直接拿过来使用。


2018-01-31 19:41:19 YuAnHandSome 阅读数 1482
  • Unity3DUI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    984 人正在学习 去看看 伍晓波

Unity UI EventTrigger 动态添加UI事件

UI中点击、按下、抬起、进入、退出、拖拽等事件,可以引用各自的接口,实现接口中的方法来完成相应需求。但是如果一个对象身上要完成很多事件,引用大量接口就显得麻烦了。为了避免引用借口过多,实现动态绑定事件可以用EventTrigger组件来完成。下面给大家演示一下EventTrigger组件的使用方法,以及如何在代码里动态添加所需的事件。

EventTrigger的在Inspector中使用

EventTrigger在Inspector面板的属性:在代码中写好对应事件的方法,选出要添加Event Type,像Button一样把方法拖拽到对应的EventType上即可,如下图:

EventTrigger的在带代码动态绑定事件使用

代码中动态创建要有以下几个步骤:
1、实例化所有委托的列表
2、新建所需的事件
3、注册eventID
4、新建callback
5、设置对应事件的内容
6、绑定事件
7、把事件添加到委托列表

以上7步是EventTrigger动态添加事件的步骤,按照步骤来就很容易了。
下面是演示效果

EventTrigger用好动态添加事件,会很方便,省去很多接口,随便一个UI控件加上EventTrigger组件后,所有的交互都可以很容易的完成。下面附上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// using namespace
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class EventTriggerTest : MonoBehaviour {

    Text testT;
    EventTrigger testET;
    private void Start()
    {
        testT = transform.Find("Text").GetComponent<Text>();
        
        testET = gameObject.GetComponent<EventTrigger>();
        if (testET == null)
            testET = gameObject.AddComponent<EventTrigger>();

        // 实例化委托列表
        testET.triggers = new List<EventTrigger.Entry>();

        // 注册事件
        EventTrigger.Entry entryPointerEnter = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerExit = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerDown = new EventTrigger.Entry();
        EventTrigger.Entry entryPointerUp = new EventTrigger.Entry();
        EventTrigger.Entry entryDrag = new EventTrigger.Entry();

        // 实例化eventID
        entryPointerEnter.eventID = EventTriggerType.PointerEnter;
        entryPointerExit.eventID = EventTriggerType.PointerExit;
        entryPointerDown.eventID = EventTriggerType.PointerDown;
        entryPointerUp.eventID = EventTriggerType.PointerUp;
        entryDrag.eventID = EventTriggerType.Drag;

        // 实例化callback
        entryPointerEnter.callback = new EventTrigger.TriggerEvent();
        entryPointerExit.callback = new EventTrigger.TriggerEvent();
        entryPointerDown.callback = new EventTrigger.TriggerEvent();
        entryPointerUp.callback = new EventTrigger.TriggerEvent();
        entryDrag.callback = new EventTrigger.TriggerEvent();

        // 设置事件
        UnityAction<BaseEventData> pointerEnterCB = new UnityAction<BaseEventData>(OnPointerEnterCBTarget);
        UnityAction<BaseEventData> pointerExitCB = new UnityAction<BaseEventData>(OnPointerExitCBTarget);
        UnityAction<BaseEventData> pointerDownCB = new UnityAction<BaseEventData>(OnPointerDownCBTarget);
        UnityAction<BaseEventData> pointerUpCB = new UnityAction<BaseEventData>(OnPointerUpCBTarget);
        UnityAction<BaseEventData> DragCB = new UnityAction<BaseEventData>(OnDragCBTarget);

        // 绑定事件
        entryPointerEnter.callback.AddListener(pointerEnterCB);
        entryPointerExit.callback.AddListener(pointerExitCB);
        entryPointerDown.callback.AddListener(pointerDownCB);
        entryPointerUp.callback.AddListener(pointerUpCB);
        entryDrag.callback.AddListener(DragCB);

        // 添加到委托列表
        testET.triggers.Add(entryPointerEnter);
        testET.triggers.Add(entryPointerExit);
        testET.triggers.Add(entryPointerDown);
        testET.triggers.Add(entryPointerUp);
        testET.triggers.Add(entryDrag);
    }
    // 进入 要做的事
    void OnPointerEnterCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerEnter";
        Debug.Log("write here when PointerDown");
    }
    // 离开 要做的事
    void OnPointerExitCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerExit";
        Debug.Log("write here when PointerExit");
    }
    // 按下 要做的事
    void OnPointerDownCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerDown";
        Debug.Log("write here when PointerDown");
    }
    // 抬起 要做的事
    void OnPointerUpCBTarget(BaseEventData baseEventData)
    {
        testT.text = "PointerUp";
        Debug.Log("write here when PointerUp");
    }
    // 点击 要做的事
    void OnDragCBTarget(BaseEventData baseEventData)
    {
        transform.position = Input.mousePosition;
        testT.text = "Drag:" + Input.mousePosition;
        Debug.Log("write here when PointerClick");
    }
}

其他

更多Blog请见:https://yiyuan1130.github.io/
Github地址:https://github.com/yiyuan1130

2019-06-04 12:35:15 shuai1210 阅读数 49
  • Unity3DUI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    984 人正在学习 去看看 伍晓波

好记性不如烂笔头,记一下方便以后翻阅。

在一些游戏中有些界面需要展示3d模型,并且可以进行旋转等操作,例如装备展示,英雄信息等界面,一方面要展示UI信息,一方面要展示角色模型。解决这种问题最简单粗暴的就是直接设置两个摄像机,每一个UICamera,一个3d模型Camera,然后摄像机成像进行叠加,但是这样的话可能有一些UI层级的问题,今天文章记录的是另一种方式来展示3d模型。

创建一个RenderTexture, 然后创建一个RawImage,并将刚才创建的RenderTexture赋值给RawIamge,(当然也可以选择Image来显示,这样需要创建一个Material,将Material的shader设置为Unlit/TransParent,然后选择刚才创建的RenderTexture,最后将设置好的Material赋值给Image就可以了) 设置创建一个摄像机,摄像机的projection属性设置为Orthographic,然后将刚才创建的RenderTexture赋值给摄像机的Target Texture,这样就可以看到展示的模型了,并且不影响UI的层级显示。

 

但是这样运行后会发现3d模型在旋转的时候有重影

这就比较尴尬了。

不慌,调整一个摄像机就可以了

呐,就这样。

现在运行就可以在UI上看到展示的3d模型了,并且可以进行旋转的操作。

2016-03-02 10:14:25 honey199396 阅读数 4333
  • Unity3DUI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    984 人正在学习 去看看 伍晓波

Unity3D – 简单的UI管理结构

使用Unity3D做一些小游戏原型的时候,虽然我们想做UI,但是又没有美术的支持,我们使用一个简单的UI模板,所有不需要做UI的小游戏直接使用就行了,也不必要每次都要自己写。

首先写一个UIBase类,所有的UI类都继承这个类就可以了 。

代码块

UIBase类

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using DG.Tweening;
/// <summary>
/// UI控制器基类
/// </summary>
public abstract class UIBase : MonoBehaviour
{
    private Transform m_Transform;
    //UI是否已经显示
    [HideInInspector]
    public bool m_SelfShowed = false;
    // UI是否被初始化
    private bool m_Inited = false;
    private Vector3 m_DefaultPos = Vector3.zero;
    private CanvasGroup m_CanvasGroup;
    void Awake()
    {
        m_Transform = transform;
        m_DefaultPos = m_Transform.position;
    }
    void Start () {
        InitSuper ();
    }
    public void InitSuper()
    {
        if (m_Inited)
            return;
        m_Inited = true;
        m_CanvasGroup = GetComponent<CanvasGroup> ();
        if(m_CanvasGroup == null){
            gameObject.AddComponent<CanvasGroup> ();
            m_CanvasGroup = GetComponent<CanvasGroup> ();
            m_CanvasGroup.alpha = 1;
            m_CanvasGroup.ignoreParentGroups = false;
            m_CanvasGroup.interactable = false;
            m_CanvasGroup.blocksRaycasts = false;
        }
        gameObject.SetActive (true);
        Button[] buttons = GetComponentsInChildren<Button> ();
        foreach (var item in buttons) {
            Button btn = item as Button;
            btn.onClick.AddListener (delegate {
                this.DidOnClick (btn.gameObject);
            });
        }
        DidInitUI ();
    }
    public void ShowUI()
    {
        if (!m_SelfShowed) {
            InitSuper ();
            DidShowUI ();
        }
    }
    public void HideUI()
    {
        if (m_SelfShowed) {
            InitSuper ();
            DidHideUI ();
        }
    }
    public void OpenActivity()
    {
        m_SelfShowed = true;
        gameObject.SetActive (true);
        m_Transform.position = m_DefaultPos + new Vector3 (Screen.width, 0, 0);
        m_Transform.DOMoveX (m_DefaultPos.x, 0.2f);
    }
    public void CloseActivity ()
    {
        m_SelfShowed = false;
        float outPos = m_Transform.position.x - Screen.width;
        m_Transform.DOMoveX (outPos, 0.2f).OnComplete (delegate {
            gameObject.SetActive(false);
        });
    }
    /// <summary>
    /// 在Start中初始化UI的操作
    /// </summary>
    public abstract void DidInitUI ();
    /// <summary>
    /// 执行显示UI的操作
    /// </summary>
    public abstract void DidShowUI ();
    /// <summary>
    /// 执行关闭UI的操作
    /// </summary>
    public abstract void DidHideUI ();
    /// <summary>
    /// 注册按钮点击事件
    /// </summary>
    /// <param name="sender">Sender.</param>
    public abstract void DidOnClick (GameObject sender);
}

所有继承UIBase的类只需要实现几个抽象方法就可以了,ShowUI和HideUI的具体实现都放到了DidShowUI()和DidHideUI()里面,基类还用了DoTween来实现一个简单的打开UI,关闭UI的动画。

假如我们要做一个只有一个开始游戏按钮的主界面

新建一个类:MenuUI实现如下:

代码块

UIBase类

using UnityEngine;
using System.Collections;
public class MenuUI : UIBase {
    public override void DidInitUI (){ }
    public override void DidShowUI ()
    {
        OpenActivity ();
    }
    public override void DidHideUI ()
    {
        CloseActivity ();
    }
    public override void DidOnClick (GameObject sender)
    {
        switch (sender.name) {
        case "ButtonStart":
            GameManager.Instance.GameStart ();
            break;
        default:
            break;
        }
    }
}

点击按钮开始游戏。
其他相应的UI也可以使用这种方法。

下面是UI管理类,让你建立简单的UI不需要做任何操作就可以运行游戏了。

新建一个叫UIManager的类
实现如下:

代码块

using UnityEngine;
using System.Collections;
using MicroGame;
using System.Collections.Generic;
public class UIManager : Singleton<UIManager> {
    /// <summary>
    /// UI信息
    /// </summary>
    [System.Serializable]
    public struct UIInfo
    {
        public UIType type;
        public UIBase ui;
    }
    /// <summary>
    /// UI类型
    /// </summary>
    public enum UIType
    {
        _NONE,
        _MENU,          // 进入游戏主界面
        _GAMEOVER,      // 游戏结束界面
        _INGAME,        // 答题界面
        _CHOOSELEVEL    // 选关界面
    }
    // 所有UI信息
    [SerializeField]
    private UIInfo[] m_UIInfo;
    // 保存已经显示的UI
    [SerializeField]
    private Stack<UIBase> m_UIStack;
    // 当前UI类型
    private UIType m_CurrentType = UIType._NONE;
    // 即将打开UI的类型
    private UIType m_NextType = UIType._NONE;
    void Start () {
        InitUI ();
    }
    #region private funcs
    // 初始化所有UI
    void InitUI()
    {
        foreach (var item in m_UIInfo) {
            if (item.type == UIType._MENU) {
                ShowUI (item.type);
            } else {
                item.ui.gameObject.SetActive (false);
            }
        }
    }
    // 根据UI类型获取UI实例
    UIBase GetUI(UIType type)
    {
        foreach (var item in m_UIInfo) {
            if (item.type == type)
                return item.ui;
        }
        return null;
    }
    // 根据UI实例获取UI类型
    UIType GetType(UIBase ui)
    {
        foreach (var item in m_UIInfo) {
            if (item.ui == ui)
                return item.type;
        }
        return UIType._NONE;
    }
    #endregion
    #region public funcs
    public void ShowUI(UIType type)
    {
        if (type == m_CurrentType) {
            return;
        }
        if (m_CurrentType != UIType._NONE) {
            GetUI (m_CurrentType).HideUI ();
        }
        if (type != UIType._NONE && m_NextType == UIType._NONE) {
            m_NextType = type;
            GetUI (m_NextType).ShowUI ();
        }
        m_CurrentType = m_NextType;
        m_NextType = UIType._NONE;
    }
    public void HideUI(UIType type){ }
    #endregion
}

要打开某个UI只需要调用一下UIManager.Instance.ShowUI (UIType._GAMEOVER);
就可以了。这样是不是很方便呢。

–Rocky

2016-10-14 14:30:59 aiyan1111111 阅读数 7865
  • Unity3DUI系统(UGUI)初级入门

    本课程主要介绍Unity3d的UI系统(UGUI),先对UGUI做一个总体概述,之后对每个UI控件逐一进行详细讲述,内容包括控件的作用、设置方法、使用场景及属性细节,帮助大家熟练使用UGUI设计游戏的交互界面。

    984 人正在学习 去看看 伍晓波

说明

在移动端使用手指触碰情况下或者存在鼠标点击情况下,很多时候我们都需要对所点击到的东西做判断——是否点击在UI或者是否点击到3D物体上等,判断点击在UI上的时候是否同时点击到了3D物体上。。。

点击到UI

这里我使判断的是Unity中所自带的UGUI 系统,判断是否点击到UI上:
UGUI系统提供的方法如下所示:
这里写图片描述
然后通过判断移动端、PC端作出相应的操作:
这里写图片描述

点击到3D物体

这里我通过射线检测方式,判断是否点击到了3D物体,但这里存在一个缺陷,3D物体必须具有碰撞体:
这里写图片描述

完整代码

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

/// <summary>
/// 全局Click检测
/// </summary>
public class ClickEvent : MonoBehaviour
{

    private RaycastHit ObjHit;
    private Ray CustomRay;
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
#if UNITY_ANDROID || UNITY_IPHONE
            //移动端判断如下
            if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
#else
            //PC端判断如下
            if (EventSystem.current.IsPointerOverGameObject())
#endif
            {
                Debug.Log("当前点击在UI上" + EventSystem.current.currentSelectedGameObject);
            }
            else
            {
              //从摄像机发出一条射线,到点击的坐标
                CustomRay = Camera.main.ScreenPointToRay(Input.mousePosition);
                //显示一条射线,只有在scene视图中才能看到
                Debug.DrawLine(CustomRay.origin, ObjHit.point, Color.red, 2);
                if (Physics.Raycast(CustomRay, out ObjHit, 100))
                {
                    if (ObjHit.collider.gameObject != null)
                    {
                        Debug.Log("Click Object:" + ObjHit.collider.gameObject);
                    }
                }
                else
                {
                    Debug.Log("Click Null");
                }
            }
        }
    }

}

Unity UI嵌入3D模型

阅读数 1297

Unity3D_UI

阅读数 196

没有更多推荐了,返回首页