UI系统

版权声明:转载或者引用本文内容请注明来源及原作者 https://blog.csdn.net/TIANHUNYISHUI/article/details/88814853
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>
		public static void Init (RenderMode renderMode,
			Camera camera,
			CanvasScaler.ScaleMode scaleMode,
			Vector2 resolution) {
			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;
		}

		/// <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;
				panel.Init (panelName, gameObject);
				Instance.m_PanelMap[panelName] = panel;
				Instance.m_PanelList.Add (panel);
			}

			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) {
				foreach (var panel in m_PanelList) {
					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);
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/TIANHUNYISHUI/article/details/88814853