using System; using System.Collections.Generic; using System.Linq; using AibisDream.Framework; using AibisDream.UI; using AibisDream.Utility; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace AibisDream { public class UIManager : Kit.Singleton, IUIManager { #region 索引 private Dictionary _panelPool; private readonly Stack _panelStack = new(); public RectTransform Canvas { get; private set; } public Vector2 Resolution { get; set; } public Camera UICamera { get; private set; } public RectTransform DialogCanvas { get; private set; } private GraphicRaycaster _raycaster; private EventSystem _pointerEventSystem; private PointerEventData _pointerEventData; private readonly List _pointerRaycastResults = new(); private DeveloperModePanel _developerModePanel; #endregion public override void OnSingletonInit() { InitRefs(); } private void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { if (DeveloperModeGate.IsEnabled && _developerModePanel != null && _developerModePanel.HandleEscape()) { return; } if (TryGetPanel(out var inGameTerminal) && inGameTerminal.HandleEscape()) { return; } if (TryGetPanel(out var terminal) && terminal.HandleEscape()) { return; } if (GameManager.Instance != null && GameManager.Session.CanPause) { GetPanel()?.Open(InGameTerminalPage.Setting); } } if (DeveloperModeGate.IsEnabled && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.R)) { _developerModePanel?.TogglePanel(); } } private void InitRefs() { UICamera = transform.Find("UI Camera").GetComponent(); // 获取Canvas Canvas = transform.Find("UI Canvas").GetComponent(); DialogCanvas = transform.Find("Dialog Canvas").GetComponent(); // 获取 GraphicRaycaster _raycaster = Canvas.GetComponent(); _developerModePanel = GetComponentsInChildren(true) .FirstOrDefault(panel => panel.IsConfigured); if (_developerModePanel == null) { var infoPanel = transform.Find("UI Canvas/Info Panel"); if (infoPanel != null) { _developerModePanel = infoPanel.GetComponentsInChildren(true) .FirstOrDefault(panel => panel.IsConfigured); } } // 获取Panel var panels = Canvas.GetComponentsInChildren(true); _panelPool = new Dictionary(); foreach (var panel in panels) { _panelPool[panel.GetType()] = panel; panel.Initialize(); } EnumEventSystem.Global.Register(GameLifecycleEvent.ApplicationReady, OnAppStart); EnumEventSystem.Global.Register(GameLifecycleEvent.SessionStarted, OnGameStart); EnumEventSystem.Global.Register(GameLifecycleEvent.SessionEnded, OnGameQuit); } private void OnAppStart() { // 游戏打开 ShowPanel(); ShowPanel(); ShowPanel(); HidePanel(); HidePanel(); HidePanel(); } private void OnGameStart() { // 开始游戏 HidePanel(); HidePanel(); ShowPanel(); } private void OnGameQuit() { HidePanel(); ShowPanel(); } public void ShowPanel(Action call = null) where T : class, IUIPanel { var type = typeof(T); // 从缓存中检查panel if (_panelPool.TryGetValue(type, out var panel)) { if (panel.IsOpen) return; if (panel.IsCloseable) _panelStack.Push(panel); panel.Show(); call?.Invoke(panel as T); } else { Debug.Log($"panel {type} 未注册"); } } public void HidePanel() where T : IUIPanel { var type = typeof(T); // 从缓存中检查panel if (_panelPool.TryGetValue(type, out var panel)) { if (!panel.IsOpen) return; if (panel.IsCloseable) _panelStack.Pop(); panel.Hide(); } else { Debug.Log($"panel {type} 未注册"); } } private void HidePanel(T panel) where T : IUIPanel { if (_panelPool.ContainsValue(panel)) { if (!panel.IsOpen) return; if (panel.IsCloseable) _panelStack.Pop(); panel.Hide(); } else { Debug.Log($"panel {typeof(T)} 未注册"); } } public T GetPanel() where T : class, IUIPanel { if (_panelPool.TryGetValue(typeof(T), out var panel)) { return panel as T; } Debug.Log($"没有找到{typeof(T)}"); return null; } public bool TryGetPanel(out T panel) where T : class, IUIPanel { panel = null; if (_panelPool == null) { return false; } if (_panelPool.TryGetValue(typeof(T), out var rawPanel)) { panel = rawPanel as T; } return panel != null; } public void ShowPreferredLoading() { if (TryGetPanel(out var terminalLoading)) { ShowPanel(); terminalLoading.SetProgress(0f); } else { GetPanel()?.ShowLoading(); } } public void SetPreferredLoadingProgress(float progress) { if (TryGetPanel(out var terminalLoading)) { terminalLoading.SetProgress(progress); } } public void HidePreferredLoading() { if (TryGetPanel(out _)) { HidePanel(); } GetPanel()?.HideLoading(); } public static Vector3 GetDialogUIPos(Vector3 screenPos) { // 转换为UI坐标 RectTransformUtility.ScreenPointToLocalPointInRectangle( Instance.DialogCanvas, screenPos, Instance.UICamera, out Vector2 localPoint); return localPoint; } public bool ScreenPointToLocalPointInRectangle(RectTransform rectTransform, Vector2 screenPos, out Vector2 localPoint) { return RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPos, UICamera, out localPoint); } /// /// 检查屏幕坐标是否命中主 UI Canvas 上会接收射线的元素。 /// 对话 Canvas 不在此范围内,因此点击对话画面本身仍可正常推进。 /// public bool IsPointerOverUI(Vector2 screenPosition) { var eventSystem = EventSystem.current; if (eventSystem == null || _raycaster == null) { return false; } if (_pointerEventData == null || _pointerEventSystem != eventSystem) { _pointerEventSystem = eventSystem; _pointerEventData = new PointerEventData(eventSystem); } _pointerEventData.Reset(); _pointerEventData.position = screenPosition; _pointerRaycastResults.Clear(); _raycaster.Raycast(_pointerEventData, _pointerRaycastResults); if (_pointerRaycastResults.Count == 0) { return false; } var topResult = _pointerRaycastResults[0]; return topResult.gameObject.GetComponentInParent() == null; } /// /// 检查鼠标是否在指定标记的 UI 区域上 /// /// 区域标识符,需要在 UIRegionMarker 组件中配置 /// 如果鼠标在指定区域上返回 true,否则返回 false public bool IsOverRegion(string regionTag) { if (string.IsNullOrEmpty(regionTag)) { return false; } // 如果鼠标不在 UI 上,直接返回 false if (!EventSystem.current.IsPointerOverGameObject()) { return false; } // 使用 GraphicRaycaster 检测鼠标下的 UI 元素 var eventData = new PointerEventData(EventSystem.current) { position = Input.mousePosition }; var results = new List(); _raycaster.Raycast(eventData, results); return results.Count > 0 && results.Any(result => result.gameObject.CompareTag(regionTag)); } } public interface IUIManager { void ShowPanel(Action call = null) where T : class, IUIPanel; void HidePanel() where T : IUIPanel; T GetPanel() where T : class, IUIPanel; RectTransform Canvas { get; } Vector2 Resolution { get; set; } // 还没想好要不要用栈 // UIPanel Pop(); // void Push(T panel) where T : UIPanel; } }