421 lines
13 KiB
C#
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;
|
|
}
|
|
}
|