2025-10-27 21:41:25 +08:00
|
|
|
|
using System;
|
2025-10-14 12:39:53 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Core
|
|
|
|
|
|
{
|
|
|
|
|
|
public enum UILayer
|
|
|
|
|
|
{
|
|
|
|
|
|
Background,
|
|
|
|
|
|
Normal,
|
|
|
|
|
|
Popup,
|
|
|
|
|
|
Top
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 单例UI管理者,控制UI的层级关系,UI的开关
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class UIManager : MonoSingleton<UIManager>
|
|
|
|
|
|
{
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public bool IsHasBackgroundUIActive
|
2025-10-14 12:39:53 +08:00
|
|
|
|
{
|
|
|
|
|
|
get
|
2025-10-27 22:13:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
return openedUIs.Values.Any(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Background]);
|
|
|
|
|
|
}
|
2025-10-14 12:39:53 +08:00
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public bool IsHasNormalUIActive
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
2025-10-27 22:13:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
return openedUIs.Values.Any(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Normal]);
|
|
|
|
|
|
}
|
2025-10-27 21:41:25 +08:00
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public bool IsHasPopupUIActive
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
2025-10-27 22:13:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
return openedUIs.Values.Any(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Popup]);
|
|
|
|
|
|
}
|
2025-10-27 21:41:25 +08:00
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public bool IsHasTopUIActive
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
2025-10-27 22:13:55 +08:00
|
|
|
|
{
|
|
|
|
|
|
return openedUIs.Values.Any(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Top]);
|
|
|
|
|
|
}
|
2025-10-27 21:41:25 +08:00
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-14 12:39:53 +08:00
|
|
|
|
private Dictionary<UILayer, Transform> layerRoots = new Dictionary<UILayer, Transform>();
|
|
|
|
|
|
private Dictionary<string, UIBase> openedUIs = new Dictionary<string, UIBase>();
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-15 21:31:13 +08:00
|
|
|
|
private IInputManager inputManager;
|
2025-10-27 21:41:25 +08:00
|
|
|
|
|
2025-10-15 21:31:13 +08:00
|
|
|
|
public void RegisterInputManager(IInputManager inputMgr)
|
|
|
|
|
|
{
|
|
|
|
|
|
inputManager = inputMgr;
|
|
|
|
|
|
}
|
2025-10-14 12:39:53 +08:00
|
|
|
|
|
|
|
|
|
|
public void RegisterLayer(UILayer layer, Transform root)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!layerRoots.ContainsKey(layer))
|
|
|
|
|
|
{
|
|
|
|
|
|
layerRoots[layer] = root;
|
|
|
|
|
|
|
|
|
|
|
|
// 注册场景中已存在的UI
|
|
|
|
|
|
// 遍历子对象
|
|
|
|
|
|
foreach (Transform child in root)
|
|
|
|
|
|
{
|
|
|
|
|
|
var uiName = child.gameObject.name;
|
|
|
|
|
|
UIBase uiBase = child.GetComponent<UIBase>();
|
|
|
|
|
|
if (uiBase != null && !openedUIs.ContainsKey(uiName))
|
|
|
|
|
|
{
|
|
|
|
|
|
openedUIs[uiName] = uiBase;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-27 22:13:55 +08:00
|
|
|
|
public void UnRegisterLayer(UILayer layer)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 先移除该层级下的UI注册
|
|
|
|
|
|
var uiToRemove = openedUIs.Values.Where(ui => ui.transform.parent == layerRoots[layer]).ToList();
|
|
|
|
|
|
foreach (var ui in uiToRemove)
|
|
|
|
|
|
{
|
|
|
|
|
|
openedUIs.Remove(ui.gameObject.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 然后移除层级根节点
|
|
|
|
|
|
if (layerRoots.ContainsKey(layer))
|
|
|
|
|
|
{
|
|
|
|
|
|
layerRoots.Remove(layer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-14 12:39:53 +08:00
|
|
|
|
public T OpenUI<T>(UILayer layer = UILayer.Normal) where T : Component
|
|
|
|
|
|
{
|
|
|
|
|
|
string uiName = typeof(T).Name;
|
|
|
|
|
|
if (openedUIs.ContainsKey(uiName))
|
|
|
|
|
|
{
|
|
|
|
|
|
openedUIs[uiName].Show();
|
|
|
|
|
|
UpdateCursorState();
|
|
|
|
|
|
return openedUIs[uiName] as T;
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-14 12:39:53 +08:00
|
|
|
|
// 加载UI预制体
|
|
|
|
|
|
GameObject prefab = Resources.Load<GameObject>("UI/" + uiName); // 从 Resources/UI 文件夹加载UI预制体
|
|
|
|
|
|
if (prefab == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("UI Prefab not found: " + uiName);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameObject uiObj = Instantiate(prefab, layerRoots[layer]); // 实例化并设置父对象
|
|
|
|
|
|
UIBase uiBase = uiObj.GetComponent<UIBase>(); // 获取UIBase组件
|
|
|
|
|
|
openedUIs[uiName] = uiBase; // 注册到字典中
|
|
|
|
|
|
uiBase.Show(); // 显示UI
|
|
|
|
|
|
UpdateCursorState(); // 更新鼠标状态
|
|
|
|
|
|
return uiBase as T;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void CloseUI<T>() where T : Component
|
|
|
|
|
|
{
|
|
|
|
|
|
string uiName = typeof(T).Name;
|
|
|
|
|
|
if (openedUIs.ContainsKey(uiName))
|
|
|
|
|
|
{
|
|
|
|
|
|
openedUIs[uiName].Hide();
|
|
|
|
|
|
UpdateCursorState();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public void ClosePopupUI()
|
|
|
|
|
|
{
|
2025-10-27 22:13:55 +08:00
|
|
|
|
var popupUIs = openedUIs.Values.Where(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Popup]);
|
2025-10-27 21:41:25 +08:00
|
|
|
|
foreach (var ui in popupUIs)
|
|
|
|
|
|
{
|
|
|
|
|
|
ui.Hide();
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
UpdateCursorState();
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
public void CloseTopUI()
|
|
|
|
|
|
{
|
2025-10-27 22:13:55 +08:00
|
|
|
|
var topUIs = openedUIs.Values.Where(ui =>
|
|
|
|
|
|
ui.gameObject.activeSelf && ui.transform.parent == layerRoots[UILayer.Top]);
|
2025-10-27 21:41:25 +08:00
|
|
|
|
foreach (var ui in topUIs)
|
|
|
|
|
|
{
|
|
|
|
|
|
ui.Hide();
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-27 21:41:25 +08:00
|
|
|
|
UpdateCursorState();
|
|
|
|
|
|
}
|
2025-10-14 12:39:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 来回切换UI状态,按同一个键实现UI的开关
|
|
|
|
|
|
public void SwitchUI<T>(UILayer layer = UILayer.Normal) where T : Component
|
|
|
|
|
|
{
|
|
|
|
|
|
string uiName = typeof(T).Name;
|
|
|
|
|
|
if (openedUIs.ContainsKey(uiName) && openedUIs[uiName].gameObject.activeSelf)
|
|
|
|
|
|
{
|
|
|
|
|
|
CloseUI<T>();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenUI<T>(layer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Dictionary<UILayer, List<GameObject>> GetExistingUIsByLayer()
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = new Dictionary<UILayer, List<GameObject>>();
|
|
|
|
|
|
foreach (var kvp in layerRoots)
|
|
|
|
|
|
{
|
|
|
|
|
|
var layer = kvp.Key;
|
|
|
|
|
|
var root = kvp.Value;
|
|
|
|
|
|
var uiList = new List<GameObject>();
|
|
|
|
|
|
foreach (Transform child in root)
|
|
|
|
|
|
{
|
|
|
|
|
|
UIBase uiBase = child.GetComponent<UIBase>();
|
|
|
|
|
|
if (uiBase != null)
|
|
|
|
|
|
uiList.Add(uiBase.gameObject);
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-14 12:39:53 +08:00
|
|
|
|
result[layer] = uiList;
|
|
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-14 12:39:53 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateCursorState()
|
|
|
|
|
|
{
|
2025-10-27 22:13:55 +08:00
|
|
|
|
if (inputManager == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
bool shouldLockCursor = !(IsHasPopupUIActive || IsHasTopUIActive);
|
2025-10-14 12:39:53 +08:00
|
|
|
|
if (shouldLockCursor)
|
|
|
|
|
|
{
|
2025-10-15 21:31:13 +08:00
|
|
|
|
inputManager.SetCursorState(false, CursorLockMode.Locked);
|
2025-10-14 12:39:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-10-15 21:31:13 +08:00
|
|
|
|
inputManager.SetCursorState(true, CursorLockMode.None);
|
2025-10-14 12:39:53 +08:00
|
|
|
|
}
|
2025-10-27 22:13:55 +08:00
|
|
|
|
|
2025-10-15 21:31:13 +08:00
|
|
|
|
inputManager.SetInputForLook(shouldLockCursor);
|
|
|
|
|
|
inputManager.SetInputForMove(shouldLockCursor);
|
2025-10-14 12:39:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|