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);
}
}
}
}