Unity UI系统

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Framework
{
    /// <summary>
    /// UI系统
    /// </summary>
    [RequireComponent(typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster))]
    [RequireComponent(typeof(UnityEngine.EventSystems.EventSystem), typeof(StandaloneInputModule))]
    public class UISystem : MonoSingleton<UISystem>
    {
        /// <summary>
        /// 名字分隔符
        /// </summary>
        private const char SPLIT_NAME = '.';

        /// <summary>
        /// 画布对象
        /// </summary>
        public static Canvas Canvas { get; private set; }

        /// <summary>
        /// 画布缩放对象
        /// </summary>
        public static CanvasScaler CanvasScaler { get; private set; }

        /// <summary>
        /// 图像射线接收器
        /// </summary>
        public static GraphicRaycaster GraphicRaycaster { get; private set; }

        /// <summary>
        /// 引擎事件系统
        /// </summary>
        public static UnityEngine.EventSystems.EventSystem EventSystem { get; private set; }

        /// <summary>
        /// UI摄像机
        /// </summary>
        public static Camera Camera { get { return Canvas == null ? null : Canvas.worldCamera; } }

        /// <summary>
        /// 画布大小
        /// </summary>
        public static Vector2 CanvasSize { get { return (Instance.transform as RectTransform).sizeDelta; } }

        /// <summary>
        /// 屏幕到UI缩放比例
        /// </summary>
        public static Vector2 ScreenToUIScale { get { return new Vector2(CanvasSize.x / Screen.width, CanvasSize.y / Screen.height); } }

        /// <summary>
        /// UI到屏幕缩放比例
        /// </summary>
        public static Vector2 UIToScreenScale { get { return new Vector2(Screen.width / CanvasSize.x, Screen.height / CanvasSize.y); } }

        /// <summary>
        /// 世界到UI缩放比例
        /// </summary>
        public static Vector2 WorldToUIScale { get { return new Vector2(1 / Canvas.transform.localScale.x, 1 / Canvas.transform.localScale.y); } }

        /// <summary>
        /// UI到世界缩放比例
        /// </summary>
        public static Vector2 UIToWorldScale { get { return new Vector2(Canvas.transform.localScale.x, Canvas.transform.localScale.y); } }

        /// <summary>
        /// 世界到屏幕缩放比例
        /// </summary>
        public static Vector2 WorldToScreenScale { get { return new Vector2(WorldToScreenScale.x * UIToScreenScale.x, WorldToScreenScale.y * UIToScreenScale.y); } }

        /// <summary>
        /// 屏幕到世界缩放比例
        /// </summary>
        public static Vector2 ScreenToWorldScale { get { return new Vector2(ScreenToUIScale.x * UIToWorldScale.x, ScreenToUIScale.y * UIToWorldScale.y); } }

        /// <summary>
        /// 面板表[键:面板名 值:面板对象]
        /// </summary>
        private Dictionary<string, UIPanel> m_PanelMap = new Dictionary<string, UIPanel>();

        /// <summary>
        /// 面板链表
        /// </summary>
        private List<UIPanel> m_PanelList = new List<UIPanel>();

        /// <summary>
        /// 异步回调表[键:面板名 值:回调]
        /// </summary>
        private Dictionary<string, Action<UIPanel>> m_AsyncCallbackMap = new Dictionary<string, Action<UIPanel>>();

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="renderMode">渲染模式</param>
        /// <param name="camera">摄像机</param>
        /// <param name="scaleMode">缩放模式</param>
        /// <param name="resolution">自适应分辨率</param>
        /// <param name="ppu">单位参考像素</param>
        public static void Init(RenderMode renderMode,
            Camera camera,
            CanvasScaler.ScaleMode scaleMode,
            Vector2 resolution, float ppu)
        {
            Canvas = Instance.gameObject.GetComponent<Canvas>();
            CanvasScaler = Instance.gameObject.GetComponent<CanvasScaler>();
            GraphicRaycaster = Instance.gameObject.GetComponent<GraphicRaycaster>();
            EventSystem = Instance.gameObject.GetComponent<UnityEngine.EventSystems.EventSystem>();

            Canvas.planeDistance = 0;
            Canvas.renderMode = renderMode;
            Canvas.worldCamera = camera;
            CanvasScaler.uiScaleMode = scaleMode;
            CanvasScaler.referenceResolution = resolution;
            Canvas.referencePixelsPerUnit = ppu;
        }

        /// <summary>
        /// 打开面板
        /// </summary>
        /// <param name="panelName">面板名</param>
        /// <param name="type">面板类型</param>
        /// <returns></returns>
        public static UIPanel Open(string panelName, Type type)
        {
            UIPanel panel = Get(panelName);
            if (panel == null)
            {
                GameObject asset = null;
                asset = Resources.Load<GameObject>(panelName);
                GameObject gameObject = Instantiate(asset);
                gameObject.name = asset.name;
                gameObject.transform.SetParent(Instance.transform, false);

                panel = Activator.CreateInstance(type) as UIPanel;
                Instance.m_PanelMap[panelName] = panel;
                Instance.m_PanelList.Add(panel);

                panel.Init(panelName, gameObject);
            }

            panel.Enabled = true;

            return panel;
        }

        /// <summary>
        /// 异步打开面板
        /// </summary>
        /// <param name="panelName">面板名</param>
        /// <param name="type">面板类型</param>
        /// <param name="openCallback">打开回调</param>
        public static void OpenAsync(string panelName, Type type, Action<UIPanel> openCallback = null)
        {
            UIPanel panel = Get(panelName);
            if (panel == null)
            {
                Action<UIPanel> callback = null;
                if (Instance.m_AsyncCallbackMap.TryGetValue(panelName, out callback))
                {
                    callback -= openCallback;
                    callback += openCallback;
                    Instance.m_AsyncCallbackMap[panelName] = callback;
                }
                else
                {
                    Instance.m_AsyncCallbackMap[panelName] = openCallback;
                    Instance.StartCoroutine(OnLoadComplete(panelName, type));
                }
            }
            else
            {
                if (openCallback != null)
                {
                    openCallback.Invoke(panel);
                }
                panel.Enabled = true;
            }
        }

        /// <summary>
        /// 更新启用的面板
        /// </summary>
        private void Update()
        {
            if (m_PanelList != null)
            {
                for (int i =0; i < m_PanelList.Count; i ++)
                {
                    UIPanel panel = m_PanelList[i];
                    if (!panel.Enabled)
                        continue;

                    panel.OnUpdate();
                }
            }
        }

        /// <summary>
        /// 关闭面板
        /// </summary>
        /// <param name="panelName">面板名</param>
        /// <param name="destroy">是否销毁</param>
        public static void Close(string panelName, bool destroy = false)
        {
            UIPanel panel = Get(panelName);
            if (panel == null)
            {
                return;
            }

            if (destroy)
            {
                Instance.m_PanelMap.Remove(panelName);
                Instance.m_PanelList.Remove(panel);
                panel.OnDestroy();
                Destroy(panel.GameObject);
            }
            else
            {
                panel.Enabled = false;
            }
        }

        /// <summary>
        /// 获取面板
        /// </summary>
        /// <param name="panelName">面板名</param>
        /// <returns>返回面板</returns>
        public static UIPanel Get(string panelName)
        {
            UIPanel panel = null;
            Instance.m_PanelMap.TryGetValue(panelName, out panel);
            return panel;
        }

        /// <summary>
        /// 获取所有面板
        /// </summary>
        /// <returns></returns>
        public static UIPanel[] GetAll()
        {
            return Instance.m_PanelList.ToArray();
        }

        /// <summary>
        /// 销毁启用的面板
        /// </summary>
        private void OnDestroy()
        {
            if (m_PanelList != null)
            {
                foreach (var panel in m_PanelList)
                {
                    if (!panel.Enabled)
                        continue;

                    panel.OnDestroy();
                }
            }
        }

        /// <summary>
        /// 屏幕转UI坐标
        /// </summary>
        /// <param name="position">屏幕坐标</param>
        /// <returns>返回UI坐标</returns>
        public static Vector2 ScreenToUIPoint(Vector2 position)
        {
            RectTransform transform = Instance.transform as RectTransform;
            Vector2 point = new Vector2((position.x / Screen.width - 0.5f) * transform.sizeDelta.x,
                (position.y / Screen.height - 0.5f) * transform.sizeDelta.y);

            return point;
        }

        /// <summary>
        /// UI转屏幕坐标
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        public static Vector2 UIToScreenPoint(Vector2 position)
        {
            RectTransform transform = Instance.transform as RectTransform;
            Vector2 point = new Vector2((position.x / transform.sizeDelta.x + 0.5f) * Screen.width,
                (position.y / transform.sizeDelta.y + 0.5f) * Screen.height);

            return point;
        }

        /// <summary>
        /// 世界转UI坐标
        /// </summary>
        /// <param name="position">世界坐标</param>
        /// <returns>返回UI坐标</returns>
        public static Vector2 WorldToUIPoint(Vector3 position)
        {
            Vector2 screenPosition = WorldToScreenPoint(position);
            return ScreenToUIPoint(screenPosition);
        }

        /// <summary>
        /// UI转世界坐标
        /// </summary>
        /// <param name="position">UI坐标</param>
        /// <returns>返回世界坐标</returns>
        public static Vector3 UIToWorldPoint(Vector2 position)
        {
            Vector2 screenPosition = UIToScreenPoint(position);
            return ScreenToWorldPoint(screenPosition);
        }

        /// <summary>
        /// 世界转屏幕坐标
        /// </summary>
        /// <param name="position">世界坐标</param>
        /// <returns>返回屏幕坐标</returns>
        public static Vector3 WorldToScreenPoint(Vector3 position)
        {
            return Camera.WorldToScreenPoint(position);
        }

        /// <summary>
        /// 屏幕转世界坐标
        /// </summary>
        /// <param name="position">屏幕坐标</param>
        /// <returns>返回世界坐标</returns>
        public static Vector3 ScreenToWorldPoint(Vector3 position)
        {
            return Camera.ScreenToWorldPoint(position);
        }

        /// <summary>
        /// 加载完成回调
        /// </summary>
        /// <param name="asset"></param>
        /// <param name="arg"></param>
        private static void OnLoadComplete(object asset, object arg)
        {
            GameObject uiAsset = asset as GameObject;
            GameObject gameObject = Instantiate(uiAsset);
            gameObject.name = uiAsset.name;
            gameObject.transform.SetParent(Instance.transform, false);

            object[] args = arg as object[];
            string panelName = args[0] as string;
            Type type = args[1] as Type;

            UIPanel panel = Activator.CreateInstance(type) as UIPanel;
            panel.Init(panelName, gameObject);
            Instance.m_PanelMap[panelName] = panel;
            Instance.m_PanelList.Add(panel);

            panel.Enabled = true;
            Action<UIPanel> openCallback = Instance.m_AsyncCallbackMap[panelName];
            if (openCallback != null)
            {
                openCallback.Invoke(panel);
                Instance.m_AsyncCallbackMap.Remove(panelName);
            }
        }

        /// <summary>
        /// 异步加载完成回调
        /// </summary>
        /// <param name="panelName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private static IEnumerator OnLoadComplete(string panelName, Type type)
        {
            ResourceRequest request = Resources.LoadAsync<GameObject>(panelName);
            yield return request;
            try
            {
                GameObject gameObject = Instantiate(request.asset as GameObject);
                gameObject.name = request.asset.name;
                gameObject.transform.SetParent(Instance.transform, false);

                UIPanel panel = Activator.CreateInstance(type) as UIPanel;
                panel.Init(panelName, gameObject);
                Instance.m_PanelMap[panelName] = panel;
                Instance.m_PanelList.Add(panel);

                panel.Enabled = true;
                Action<UIPanel> openCallback = Instance.m_AsyncCallbackMap[panelName];

                if (openCallback != null)
                {
                    openCallback.Invoke(panel);
                    Instance.m_AsyncCallbackMap.Remove(panelName);
                }
            }
            catch (Exception e)
            {
                Debug.LogError("异步打开界面错误!" + panelName + " " + e);
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值