mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 12:37:12 +08:00
(client) feat:健康给予,路径优化,结算界面,商店界面 (#60)
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
This commit is contained in:
@@ -4,108 +4,52 @@ using System.Linq;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Utils;
|
||||
|
||||
namespace Base
|
||||
{
|
||||
/// <summary>
|
||||
/// UI窗口输入控制和管理类。
|
||||
/// 负责根据输入显示/隐藏UI,并根据UI状态管理游戏暂停。
|
||||
/// UI窗口输入控制和管理类。
|
||||
/// 负责根据输入显示/隐藏UI,并根据UI状态管理游戏暂停。
|
||||
/// </summary>
|
||||
public class UIInputControl : Utils.MonoSingleton<UIInputControl>, ITickUI
|
||||
public class UIInputControl : MonoSingleton<UIInputControl>, ITickUI
|
||||
{
|
||||
// 存储场景中所有UIBase的实例
|
||||
private List<UIBase> _allWindows = new List<UIBase>();
|
||||
// 缓存当前可见的窗口
|
||||
private readonly List<UIBase> _visibleWindows = new List<UIBase>();
|
||||
private readonly List<UIBase> _visibleWindows = new();
|
||||
|
||||
// 存储场景中所有UIBase的实例
|
||||
private List<UIBase> _allWindows = new();
|
||||
|
||||
// 标记是否需要更新可见窗口缓存和暂停状态
|
||||
private bool needUpdate = false;
|
||||
private bool needUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// 当UI窗口的可见性状态发生改变时触发的事件。
|
||||
/// <list type="bullet">
|
||||
/// <item>参数1: 发生改变的UIBase实例。</item>
|
||||
/// <item>参数2: 窗口的新可见状态 (true为显示,false为隐藏)。</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public event Action<UIBase, bool> OnWindowVisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已注册的UI窗口的总数量。
|
||||
/// 获取所有已注册的UI窗口的总数量。
|
||||
/// </summary>
|
||||
public int AllWindowCount => _allWindows.Count;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前可见的UI窗口的数量。
|
||||
/// 获取当前可见的UI窗口的数量。
|
||||
/// </summary>
|
||||
public int VisibleWindowCount => _visibleWindows.Count;
|
||||
|
||||
public bool HasWindowOpen => _visibleWindows.Any();
|
||||
|
||||
public bool HasInputExclusionWindow { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定名称的UI窗口是否当前可见。
|
||||
/// 当脚本实例被销毁时调用。
|
||||
/// 用于在销毁时取消订阅场景加载事件,防止内存泄漏。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>如果窗口可见则返回true,否则返回false。</returns>
|
||||
public bool IsWindowVisible(string uiName)
|
||||
private void OnDestroy()
|
||||
{
|
||||
return _visibleWindows.Any(window => window != null && window.name == uiName && window.IsVisible);
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
Clock.RemoveTickUI(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定名称的UI窗口是否当前处于可见状态且占用了输入。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>如果窗口可见且占用了输入则返回true,否则返回false。</returns>
|
||||
public bool IsWindowInputOccupied(string uiName)
|
||||
{
|
||||
return _visibleWindows.Any(window => window != null && window.name == uiName && window.IsVisible && window.isInputOccupied);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据名称获取已注册的UI窗口实例。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>匹配的UIBase实例,如果未找到则返回null。</returns>
|
||||
public UIBase GetWindow(string uiName)
|
||||
{
|
||||
return _allWindows.FirstOrDefault(window => window != null && window.name == uiName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找并注册场景中所有的UI窗口,包括非激活状态的。
|
||||
/// </summary>
|
||||
private void RegisterAllWindows()
|
||||
{
|
||||
_allWindows.Clear();
|
||||
|
||||
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
||||
if (!activeScene.isLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var rootGameObject in activeScene.GetRootGameObjects())
|
||||
{
|
||||
var windows = rootGameObject.GetComponentsInChildren<UIBase>(true);
|
||||
_allWindows.AddRange(windows);
|
||||
}
|
||||
|
||||
_allWindows = _allWindows.Distinct().ToList();
|
||||
|
||||
foreach (var window in _allWindows)
|
||||
{
|
||||
if (window != null && window.gameObject != null)
|
||||
{
|
||||
window.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI逻辑更新循环,需要被外部的某个管理器在Update中调用。
|
||||
/// UI逻辑更新循环,需要被外部的某个管理器在Update中调用。
|
||||
/// </summary>
|
||||
public void TickUI()
|
||||
{
|
||||
@@ -129,10 +73,7 @@ namespace Base
|
||||
|
||||
if (window.IsVisible)
|
||||
{
|
||||
if (!window.isInputOccupied)
|
||||
{
|
||||
Hide(window);
|
||||
}
|
||||
if (!window.isInputOccupied) Hide(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -142,7 +83,72 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 公开的显示窗口方法。
|
||||
/// 当UI窗口的可见性状态发生改变时触发的事件。
|
||||
/// <list type="bullet">
|
||||
/// <item>参数1: 发生改变的UIBase实例。</item>
|
||||
/// <item>参数2: 窗口的新可见状态 (true为显示,false为隐藏)。</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public event Action<UIBase, bool> OnWindowVisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定名称的UI窗口是否当前可见。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>如果窗口可见则返回true,否则返回false。</returns>
|
||||
public bool IsWindowVisible(string uiName)
|
||||
{
|
||||
return _visibleWindows.Any(window => window != null && window.name == uiName && window.IsVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定名称的UI窗口是否当前处于可见状态且占用了输入。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>如果窗口可见且占用了输入则返回true,否则返回false。</returns>
|
||||
public bool IsWindowInputOccupied(string uiName)
|
||||
{
|
||||
return _visibleWindows.Any(window =>
|
||||
window != null && window.name == uiName && window.IsVisible && window.isInputOccupied);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据名称获取已注册的UI窗口实例。
|
||||
/// </summary>
|
||||
/// <param name="uiName">UI窗口的名称。</param>
|
||||
/// <returns>匹配的UIBase实例,如果未找到则返回null。</returns>
|
||||
public UIBase GetWindow(string uiName)
|
||||
{
|
||||
return _allWindows.FirstOrDefault(window => window != null && window.name == uiName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找并注册场景中所有的UI窗口,包括非激活状态的。
|
||||
/// </summary>
|
||||
private void RegisterAllWindows()
|
||||
{
|
||||
_allWindows.Clear();
|
||||
|
||||
var activeScene = SceneManager.GetActiveScene();
|
||||
if (!activeScene.isLoaded) return;
|
||||
|
||||
foreach (var rootGameObject in activeScene.GetRootGameObjects())
|
||||
{
|
||||
var windows = rootGameObject.GetComponentsInChildren<UIBase>(true);
|
||||
_allWindows.AddRange(windows);
|
||||
}
|
||||
|
||||
_allWindows = _allWindows.Distinct().ToList();
|
||||
|
||||
foreach (var window in _allWindows)
|
||||
if (window != null && window.gameObject != null)
|
||||
window.Hide();
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 公开的显示窗口方法。
|
||||
/// </summary>
|
||||
/// <param name="windowToShow">要显示的窗口。</param>
|
||||
public void Show(UIBase windowToShow)
|
||||
@@ -153,12 +159,8 @@ namespace Base
|
||||
{
|
||||
var windowsToHide = _visibleWindows.ToList();
|
||||
foreach (var visibleWindow in windowsToHide)
|
||||
{
|
||||
if (visibleWindow && visibleWindow != windowToShow && visibleWindow.IsVisible)
|
||||
{
|
||||
Hide(visibleWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
windowToShow.Show();
|
||||
@@ -169,7 +171,7 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据名称显示UI窗口。
|
||||
/// 根据名称显示UI窗口。
|
||||
/// </summary>
|
||||
/// <param name="uiName">要显示的UI窗口名称。</param>
|
||||
public void Show(string uiName)
|
||||
@@ -180,12 +182,13 @@ namespace Base
|
||||
Show(window);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"[UIInputControl] 未找到名称为 '{uiName}' 的窗口来显示。");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 公开的隐藏窗口方法。
|
||||
/// 公开的隐藏窗口方法。
|
||||
/// </summary>
|
||||
/// <param name="windowToHide">要隐藏的窗口。</param>
|
||||
public void Hide(UIBase windowToHide)
|
||||
@@ -200,80 +203,70 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据名称隐藏UI窗口。
|
||||
/// 根据名称隐藏UI窗口。
|
||||
/// </summary>
|
||||
/// <param name="uiName">要隐藏的UI窗口名称。</param>
|
||||
public void Hide(string uiName)
|
||||
{
|
||||
var visibleWindowToHide = _visibleWindows.FirstOrDefault(window => window != null && window.name == uiName && window.IsVisible);
|
||||
var visibleWindowToHide =
|
||||
_visibleWindows.FirstOrDefault(window => window != null && window.name == uiName && window.IsVisible);
|
||||
if (visibleWindowToHide != null)
|
||||
{
|
||||
Hide(visibleWindowToHide);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning($"[UIInputControl] 未找到名称为 '{uiName}' 且当前可见的窗口来隐藏。");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏所有当前可见的UI窗口。
|
||||
/// 隐藏所有当前可见的UI窗口。
|
||||
/// </summary>
|
||||
public void HideAll()
|
||||
{
|
||||
var windowsToHide = _visibleWindows.ToList();
|
||||
foreach (var visibleWindow in windowsToHide)
|
||||
{
|
||||
if (visibleWindow != null && visibleWindow.IsVisible)
|
||||
{
|
||||
Hide(visibleWindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据当前所有可见窗口的 needPause 属性来更新游戏时钟的暂停状态。
|
||||
/// 根据当前所有可见窗口的 needPause 属性来更新游戏时钟的暂停状态。
|
||||
/// </summary>
|
||||
private void UpdatePauseState()
|
||||
{
|
||||
var shouldPause = _visibleWindows.Any(w => w && w.needPause);
|
||||
if (Base.Clock.Instance.Pause != shouldPause)
|
||||
{
|
||||
Base.Clock.Instance.Pause = shouldPause;
|
||||
}
|
||||
if (Clock.Instance.Pause != shouldPause) Clock.Instance.Pause = shouldPause;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新当前可见窗口的缓存列表。
|
||||
/// 更新当前可见窗口的缓存列表。
|
||||
/// </summary>
|
||||
private void UpdateVisibleWindowsCache()
|
||||
{
|
||||
_visibleWindows.Clear();
|
||||
|
||||
HasInputExclusionWindow = false;
|
||||
var exclusiveWindow = _allWindows.FirstOrDefault(window => window && window.IsVisible && window.exclusive);
|
||||
|
||||
if (exclusiveWindow)
|
||||
{
|
||||
_visibleWindows.Add(exclusiveWindow);
|
||||
HasInputExclusionWindow = exclusiveWindow.isInputOccupied;
|
||||
}
|
||||
else
|
||||
{
|
||||
_visibleWindows.AddRange(_allWindows.Where(window => window && window.IsVisible));
|
||||
foreach (var window in _allWindows.Where(window => window.IsVisible))
|
||||
{
|
||||
if (window.isInputOccupied)
|
||||
HasInputExclusionWindow = true;
|
||||
_visibleWindows.Add(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当脚本实例被销毁时调用。
|
||||
/// 用于在销毁时取消订阅场景加载事件,防止内存泄漏。
|
||||
/// </summary>
|
||||
private void OnDestroy()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
Clock.RemoveTickUI(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoSingleton 的 OnStart 方法,在单例首次创建并激活时调用,早于普通的 Start 方法。
|
||||
/// 用于订阅场景加载事件并在首次启动时注册UI窗口。
|
||||
/// MonoSingleton 的 OnStart 方法,在单例首次创建并激活时调用,早于普通的 Start 方法。
|
||||
/// 用于订阅场景加载事件并在首次启动时注册UI窗口。
|
||||
/// </summary>
|
||||
protected override void OnStart()
|
||||
{
|
||||
@@ -282,8 +275,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当场景加载完成时调用。
|
||||
/// 用于在场景加载后重新查找并注册所有UI窗口。
|
||||
/// 当场景加载完成时调用。
|
||||
/// 用于在场景加载后重新查找并注册所有UI窗口。
|
||||
/// </summary>
|
||||
/// <param name="scene">已加载的场景。</param>
|
||||
/// <param name="mode">场景加载模式。</param>
|
||||
@@ -293,4 +286,4 @@ namespace Base
|
||||
Clock.AddTickUI(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user