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

421 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using AibisDream.UI;
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;
private InGameTerminalPanel _inGameTerminalPanel;
#endregion
public override void OnSingletonInit()
{
InitRefs();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (_inGameTerminalPanel != null && _inGameTerminalPanel.HandleEscape())
{
return;
}
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();
RegisterInGameTerminalPanel();
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();
if (_terminalPanel.HasRequiredPages())
{
_panelPool[typeof(TerminalPanel)] = _terminalPanel;
}
else
{
Debug.LogError("[UIManager] TerminalPanel is missing required pages.");
}
}
private void RegisterInGameTerminalPanel()
{
if (_panelPool.TryGetValue(typeof(InGameTerminalPanel), out var registeredPanel))
{
_inGameTerminalPanel = registeredPanel as InGameTerminalPanel;
}
else
{
_inGameTerminalPanel = Canvas.GetComponentInChildren<InGameTerminalPanel>(true);
}
if (_inGameTerminalPanel == null)
{
Debug.LogError("[UIManager] InGameTerminalPanel not found under UI Canvas. Add the in-game terminal shell and assign its Setting/Record prefab pages in the scene.");
return;
}
_inGameTerminalPanel.Initialize();
var hasPages = _inGameTerminalPanel.HasRequiredPages();
if (hasPages)
{
_panelPool[typeof(InGameTerminalPanel)] = _inGameTerminalPanel;
}
else
{
Debug.LogError("[UIManager] InGameTerminalPanel is missing required pages. Assign TerminalSettingPanel and TerminalRecordPanel on the in-game shell.");
}
}
private void OnAppStart()
{
// 游戏打开
ShowTerminalStart();
ShowPanel<PlayToolPanel>();
HidePanel<MainPanel>();
HideTerminalSetting();
HideTerminalRecord();
_inGameTerminalPanel?.Close();
HidePanel<EndPanel>();
}
private void OnGameStart()
{
// 开始游戏
HideTerminal();
_inGameTerminalPanel?.Close();
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);
}
public void HideTerminal()
{
GetPanel<TerminalPanel>()?.Close();
}
public void ShowTerminalSetting()
{
if (GameManager.Instance != null && GameManager.Instance.state.isInGame)
{
GetPanel<InGameTerminalPanel>()?.Open(InGameTerminalPage.Setting);
return;
}
GetPanel<TerminalPanel>()?.Open(TerminalPage.Setting);
}
public void HideTerminalSetting()
{
var inGame = GetPanel<InGameTerminalPanel>();
if (inGame != null && inGame.IsOpen && inGame.CurrentPage == InGameTerminalPage.Setting)
{
inGame.Close();
return;
}
var terminal = GetPanel<TerminalPanel>();
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Setting)
{
terminal.Back();
}
}
public void ShowTerminalChapter()
{
GetPanel<TerminalPanel>()?.Open(TerminalPage.Chapter);
}
public void HideTerminalChapter()
{
var terminal = GetPanel<TerminalPanel>();
if (terminal != null && terminal.IsOpen && terminal.CurrentPage == TerminalPage.Chapter)
{
terminal.Back();
}
}
public void ShowTerminalRecord()
{
var panel = GetPanel<InGameTerminalPanel>();
panel?.Open(InGameTerminalPage.Record);
}
public void HideTerminalRecord()
{
var inGame = GetPanel<InGameTerminalPanel>();
if (inGame != null && inGame.IsOpen && inGame.CurrentPage == InGameTerminalPage.Record)
{
inGame.Close();
}
}
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;
}
}