Files
aibis-dream/Assets/Scripts/UI/UIManager.cs
T

382 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.UI;
using AibisDream.UI.Terminal;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace AibisDream
{
public class UIManager : Kit.Singleton<UIManager>, IUIManager
{
#region 索引
private Dictionary<Type, IUIPanel> _panelPool;
private readonly Stack<IUIPanel> _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 TerminalPanel _terminalPanel;
#endregion
public override void OnSingletonInit()
{
InitRefs();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (_terminalPanel != null && _terminalPanel.HandleEscape())
{
return;
}
if (GameManager.Instance != null && GameManager.Instance.state.isInGame)
{
ShowTerminalSetting();
}
}
if (Input.GetKeyDown(KeyCode.C))
{
if (GetPanel<MainPanel>().IsOpen)
{
HidePanel<MainPanel>();
}
else
{
ShowPanel<MainPanel>();
}
}
}
private void InitRefs()
{
UICamera = transform.Find("UI Camera").GetComponent<Camera>();
// 获取Canvas
Canvas = transform.Find("UI Canvas").GetComponent<RectTransform>();
DialogCanvas = transform.Find("Dialog Canvas").GetComponent<RectTransform>();
// 获取 GraphicRaycaster
_raycaster = Canvas.GetComponent<GraphicRaycaster>();
// 获取Panel
var panels = Canvas.GetComponentsInChildren<IUIPanel>(true);
_panelPool = new Dictionary<Type, IUIPanel>();
foreach (var panel in panels)
{
_panelPool[panel.GetType()] = panel;
}
RegisterTerminalPanel();
EnumEventSystem.Global.Register(GameLoopEnum.AppStart, OnAppStart);
EnumEventSystem.Global.Register(GameLoopEnum.GameStart, OnGameStart);
EnumEventSystem.Global.Register(GameLoopEnum.GameQuit, OnGameQuit);
}
private void RegisterTerminalPanel()
{
if (_panelPool.TryGetValue(typeof(TerminalPanel), out var registeredPanel))
{
_terminalPanel = registeredPanel as TerminalPanel;
}
else
{
_terminalPanel = Canvas.GetComponentInChildren<TerminalPanel>(true);
}
if (_terminalPanel == null)
{
Debug.LogError("[UIManager] TerminalPanel not found under UI Canvas.");
return;
}
_terminalPanel.Initialize(Canvas);
if (_terminalPanel.HasRequiredPages())
{
_panelPool[typeof(TerminalPanel)] = _terminalPanel;
}
else
{
Debug.LogError("[UIManager] TerminalPanel is missing required pages.");
}
}
private void OnAppStart()
{
// 游戏打开
ShowTerminalStart();
ShowPanel<PlayToolPanel>();
HidePanel<MainPanel>();
HideTerminalSetting();
HideTerminalRecord();
HidePanel<EndPanel>();
}
private void OnGameStart()
{
// 开始游戏
HideTerminal();
ShowPanel<MainPanel>();
}
private void OnGameQuit()
{
HidePanel<MainPanel>();
ShowTerminalStart();
}
public void ShowPanel<T>(Action<T> 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<T>() 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>(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<T>() 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<T>(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 ShowTerminalStart()
{
GetPanel<TerminalPanel>()?.Open(TerminalPage.Start, TerminalOpenSource.MainMenu);
}
public void HideTerminal()
{
GetPanel<TerminalPanel>()?.Close();
}
public void ShowTerminalSetting()
{
var source = GameManager.Instance != null && GameManager.Instance.state.isInGame
? TerminalOpenSource.InGame
: TerminalOpenSource.MainMenu;
GetPanel<TerminalPanel>()?.Open(TerminalPage.Setting, source);
}
public void HideTerminalSetting()
{
var terminal = GetPanel<TerminalPanel>();
if (terminal == null || !terminal.IsOpen || terminal.CurrentPage != TerminalPage.Setting)
{
return;
}
if (terminal.Source == TerminalOpenSource.InGame)
{
terminal.Close();
}
else
{
terminal.Back();
}
}
public void ShowTerminalChapter()
{
GetPanel<TerminalPanel>()?.Open(TerminalPage.Chapter, TerminalOpenSource.MainMenu);
}
public void HideTerminalChapter()
{
var terminal = GetPanel<TerminalPanel>();
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Chapter)
{
terminal.Back();
}
}
public void ShowTerminalRecord()
{
GetPanel<TerminalPanel>()?.Open(TerminalPage.Record, TerminalOpenSource.InGame);
}
public void HideTerminalRecord()
{
var terminal = GetPanel<TerminalPanel>();
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Record)
{
terminal.Back();
}
}
public void CloseTerminalThen(Action action)
{
var terminal = GetPanel<TerminalPanel>();
if (terminal != null && terminal.IsOpen)
{
terminal.CloseThen(action);
return;
}
action?.Invoke();
}
public void ShowPreferredLoading()
{
if (TryGetPanel<TerminalLoadingPanel>(out var terminalLoading))
{
ShowPanel<TerminalLoadingPanel>();
terminalLoading.SetProgress(0f);
}
else
{
GetPanel<InfoPanel>()?.ShowLoading();
}
}
public void SetPreferredLoadingProgress(float progress)
{
if (TryGetPanel<TerminalLoadingPanel>(out var terminalLoading))
{
terminalLoading.SetProgress(progress);
}
}
public void HidePreferredLoading()
{
if (TryGetPanel<TerminalLoadingPanel>(out _))
{
HidePanel<TerminalLoadingPanel>();
}
GetPanel<InfoPanel>()?.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);
}
/// <summary>
/// 检查鼠标是否在指定标记的 UI 区域上
/// </summary>
/// <param name="regionTag">区域标识符,需要在 UIRegionMarker 组件中配置</param>
/// <returns>如果鼠标在指定区域上返回 true,否则返回 false</returns>
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<RaycastResult>();
_raycaster.Raycast(eventData, results);
return results.Count > 0 && results.Any(result => result.gameObject.CompareTag(regionTag));
}
}
public interface IUIManager
{
void ShowPanel<T>(Action<T> call = null) where T : class, IUIPanel;
void HidePanel<T>() where T : IUIPanel;
T GetPanel<T>() where T : class, IUIPanel;
RectTransform Canvas { get; }
Vector2 Resolution { get; set; }
// 还没想好要不要用栈
// UIPanel Pop();
// void Push<T>(T panel) where T : UIPanel;
}
}