2025-12-23 13:05:47 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-12-23 15:05:18 +08:00
|
|
|
|
/// UI窗口可见性管理器(纯性能优化模块)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 核心理念:
|
|
|
|
|
|
/// - 只控制 GameObject.SetActive(),仅影响渲染层面
|
2025-12-23 19:28:45 +08:00
|
|
|
|
/// - 不触发 UIWindow 生命周期(不调用 CloseWindow/ShowWindow)
|
2025-12-23 15:05:18 +08:00
|
|
|
|
/// - 不改变窗口逻辑状态(_isShow 保持不变)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 优化目标:
|
|
|
|
|
|
/// - 当全屏窗口打开时,自动隐藏被遮挡的下层窗口,减少 Overdraw
|
|
|
|
|
|
/// - 当全屏窗口关闭时,自动恢复被遮挡的窗口渲染
|
|
|
|
|
|
/// - 节省 GPU 绘制开销和 CPU UI 遍历开销
|
2025-12-23 13:05:47 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class UIWindowVisibilityManager
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Singleton
|
|
|
|
|
|
private static UIWindowVisibilityManager _instance;
|
|
|
|
|
|
public static UIWindowVisibilityManager Instance
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_instance == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_instance = new UIWindowVisibilityManager();
|
|
|
|
|
|
}
|
|
|
|
|
|
return _instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private UIWindowVisibilityManager() { }
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-23 15:05:18 +08:00
|
|
|
|
#region Fields
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 复用的窗口列表,避免 GC
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly List<UIWindow> _tempWindowList = new List<UIWindow>(32);
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-23 13:05:47 +08:00
|
|
|
|
#region Visibility Operations
|
|
|
|
|
|
/// <summary>
|
2025-12-23 15:05:18 +08:00
|
|
|
|
/// 处理窗口打开时的渲染优化
|
|
|
|
|
|
/// HideBelow 策略:隐藏所有被遮挡的下层窗口
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 性能优化:只控制 GameObject.SetActive(false),不影响窗口逻辑状态
|
2025-12-23 13:05:47 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="newWindow">新打开的窗口</param>
|
|
|
|
|
|
/// <param name="visibilityStrategy">可见性策略</param>
|
|
|
|
|
|
public void HandleVisibilityOnOpen(UIWindow newWindow, UIVisibilityStrategy visibilityStrategy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newWindow == null || visibilityStrategy == UIVisibilityStrategy.None)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2025-12-23 15:05:18 +08:00
|
|
|
|
// HideBelow 策略:基于渲染层级隐藏
|
2025-12-24 14:40:00 +08:00
|
|
|
|
if (visibilityStrategy == UIVisibilityStrategy.Occlusion)
|
2025-12-23 13:05:47 +08:00
|
|
|
|
{
|
2025-12-23 15:05:18 +08:00
|
|
|
|
var newWindowLayer = newWindow.uiWindowLayer;
|
|
|
|
|
|
var newWindowSiblingIndex = newWindow.transform.GetSiblingIndex();
|
|
|
|
|
|
var layerManager = UICanvasLayerManager.Instance;
|
|
|
|
|
|
|
2025-12-23 19:28:45 +08:00
|
|
|
|
// 从底层到当前层,隐藏所有应该被遮挡的窗口(只控制 GameObject.active)
|
|
|
|
|
|
for (int layer = 0; layer <= (int)newWindowLayer; layer++)
|
2025-12-23 13:05:47 +08:00
|
|
|
|
{
|
2025-12-23 15:05:18 +08:00
|
|
|
|
var windowList = layerManager.GetWindowsInLayer((UICanvasLayer)layer);
|
|
|
|
|
|
foreach (var window in windowList)
|
|
|
|
|
|
{
|
2025-12-23 19:28:45 +08:00
|
|
|
|
// 只隐藏逻辑上显示的窗口(预加载窗口不参与遮挡管理)
|
|
|
|
|
|
if (window != null && window != newWindow && window.IsShow() && window.gameObject.activeSelf)
|
2025-12-23 15:05:18 +08:00
|
|
|
|
{
|
2025-12-23 19:28:45 +08:00
|
|
|
|
bool shouldHide = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (layer < (int)newWindowLayer)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更低层:全部隐藏
|
|
|
|
|
|
shouldHide = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else // layer == (int)newWindowLayer
|
|
|
|
|
|
{
|
|
|
|
|
|
// 同层:只隐藏 SiblingIndex 更小(在下面)的窗口
|
|
|
|
|
|
var windowSiblingIndex = window.transform.GetSiblingIndex();
|
|
|
|
|
|
shouldHide = windowSiblingIndex < newWindowSiblingIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldHide)
|
|
|
|
|
|
{
|
|
|
|
|
|
window.gameObject.SetActive(false);
|
|
|
|
|
|
}
|
2025-12-23 15:05:18 +08:00
|
|
|
|
}
|
2025-12-23 13:05:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-12-23 15:05:18 +08:00
|
|
|
|
/// 处理窗口关闭时的渲染恢复
|
|
|
|
|
|
/// HideBelow 策略:恢复被遮挡窗口的渲染,直到遇到另一个 HideBelow 窗口
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 性能优化:只控制 GameObject.SetActive(true),不影响窗口逻辑状态
|
2025-12-23 13:05:47 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="closingWindow">正在关闭的窗口</param>
|
|
|
|
|
|
/// <param name="visibilityStrategy">可见性策略</param>
|
|
|
|
|
|
public void HandleVisibilityOnClose(UIWindow closingWindow, UIVisibilityStrategy visibilityStrategy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (closingWindow == null || visibilityStrategy == UIVisibilityStrategy.None)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2025-12-23 15:05:18 +08:00
|
|
|
|
// HideBelow 策略:基于渲染层级显示
|
2025-12-24 14:40:00 +08:00
|
|
|
|
if (visibilityStrategy == UIVisibilityStrategy.Occlusion)
|
2025-12-23 13:05:47 +08:00
|
|
|
|
{
|
2025-12-23 15:05:18 +08:00
|
|
|
|
var closingWindowLayer = closingWindow.uiWindowLayer;
|
|
|
|
|
|
var closingWindowSiblingIndex = closingWindow.transform.GetSiblingIndex();
|
|
|
|
|
|
var layerManager = UICanvasLayerManager.Instance;
|
|
|
|
|
|
|
|
|
|
|
|
// 从当前层开始,向下遍历所有层级,直到遇到 HideBelow 窗口
|
|
|
|
|
|
bool foundBlocker = false;
|
|
|
|
|
|
|
|
|
|
|
|
for (int layer = (int)closingWindowLayer; layer >= 0; layer--)
|
2025-12-23 13:05:47 +08:00
|
|
|
|
{
|
2025-12-23 15:05:18 +08:00
|
|
|
|
var windowList = layerManager.GetWindowsInLayer((UICanvasLayer)layer);
|
|
|
|
|
|
|
|
|
|
|
|
// 清空并复用列表,避免 GC
|
|
|
|
|
|
_tempWindowList.Clear();
|
|
|
|
|
|
|
2025-12-23 19:28:45 +08:00
|
|
|
|
// 收集需要检查的窗口(只收集逻辑上显示的窗口)
|
2025-12-23 15:05:18 +08:00
|
|
|
|
foreach (var window in windowList)
|
|
|
|
|
|
{
|
2025-12-23 19:28:45 +08:00
|
|
|
|
// ✅ 预加载的窗口(IsShow=false)不参与遮挡管理
|
|
|
|
|
|
if (window != null && window != closingWindow && window.IsShow())
|
2025-12-23 15:05:18 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 同层:只检查在关闭窗口下面的窗口
|
|
|
|
|
|
if (layer == (int)closingWindowLayer)
|
|
|
|
|
|
{
|
|
|
|
|
|
var windowSiblingIndex = window.transform.GetSiblingIndex();
|
|
|
|
|
|
if (windowSiblingIndex < closingWindowSiblingIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
_tempWindowList.Add(window);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-23 19:28:45 +08:00
|
|
|
|
// 其他层:收集所有逻辑上显示的窗口
|
2025-12-23 15:05:18 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_tempWindowList.Add(window);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按 SiblingIndex 倒序排序(从上往下检查)
|
|
|
|
|
|
_tempWindowList.Sort((a, b) => b.transform.GetSiblingIndex().CompareTo(a.transform.GetSiblingIndex()));
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历并处理窗口
|
|
|
|
|
|
foreach (var window in _tempWindowList)
|
|
|
|
|
|
{
|
|
|
|
|
|
var config = UIManager.Instance.GetWindowInfo(window.WindowName);
|
2025-12-23 19:28:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示被隐藏的窗口(只控制 GameObject.active)
|
|
|
|
|
|
if (!window.gameObject.activeSelf)
|
|
|
|
|
|
{
|
2025-12-29 18:41:38 +08:00
|
|
|
|
// // 🎯 如果窗口需要截图,在恢复前重新截图
|
|
|
|
|
|
// if (config.NeedScreenshot)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// ScreenshotManager.Instance.CaptureScreenshot();
|
|
|
|
|
|
//
|
|
|
|
|
|
// // 🎯 刷新模糊背景 texture
|
|
|
|
|
|
// RefreshBlurBackground(window);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// ScreenshotManager.Instance.ResetScreenshot();
|
|
|
|
|
|
// }
|
2025-12-25 15:01:35 +08:00
|
|
|
|
|
2025-12-23 19:28:45 +08:00
|
|
|
|
window.gameObject.SetActive(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果遇到另一个 HideBelow 窗口,停止继续向下恢复
|
|
|
|
|
|
// (因为这个窗口会负责隐藏它下面的窗口)
|
2025-12-24 14:40:00 +08:00
|
|
|
|
if (config.VisibilityStrategy == UIVisibilityStrategy.Occlusion)
|
2025-12-23 15:05:18 +08:00
|
|
|
|
{
|
|
|
|
|
|
foundBlocker = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-23 13:05:47 +08:00
|
|
|
|
|
2025-12-23 15:05:18 +08:00
|
|
|
|
if (foundBlocker)
|
2025-12-23 13:05:47 +08:00
|
|
|
|
{
|
2025-12-23 15:05:18 +08:00
|
|
|
|
break;
|
2025-12-23 13:05:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-25 15:01:35 +08:00
|
|
|
|
#region Helper Methods
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 刷新窗口的模糊背景 texture
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void RefreshBlurBackground(UIWindow window)
|
|
|
|
|
|
{
|
|
|
|
|
|
var blurTransform = window.transform.Find("GaussianBlurMask");
|
|
|
|
|
|
if (blurTransform != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var blurMask = blurTransform.GetComponent<UnityEngine.UI.RawImage>();
|
|
|
|
|
|
if (blurMask != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
blurMask.texture = ScreenshotManager.Instance.GetScreenTexture2D();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-23 13:05:47 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
}
|