2025-12-22 20:04:20 +08:00
|
|
|
|
using Cysharp.Threading.Tasks;
|
2024-08-12 19:31:50 +08:00
|
|
|
|
using DG.Tweening;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
using PhxhSDK;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
using UnityEngine;
|
2024-05-10 19:18:40 +08:00
|
|
|
|
using UniTask = Cysharp.Threading.Tasks.UniTask;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
|
2025-09-03 19:12:26 +08:00
|
|
|
|
public abstract partial class UIWindow
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2024-01-26 16:06:42 +08:00
|
|
|
|
public GameObject gameObject;
|
|
|
|
|
|
public Transform transform;
|
|
|
|
|
|
public string name;
|
|
|
|
|
|
|
2025-09-05 15:32:36 +08:00
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
private string mWindowName;
|
|
|
|
|
|
|
2025-09-03 18:19:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源引用管理器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private PhxhSDK.AssetReferenceManager _assetReferenceManager;
|
2025-12-29 20:02:22 +08:00
|
|
|
|
|
2024-10-24 17:03:31 +08:00
|
|
|
|
private bool _isCloseCbCalled;
|
2025-08-14 12:35:19 +08:00
|
|
|
|
|
|
|
|
|
|
protected bool _isShow = false;
|
2026-01-06 16:45:21 +08:00
|
|
|
|
protected bool _isPaused = false; // 窗口暂停状态(用于音乐、动画等逻辑控制)
|
2025-08-14 12:35:19 +08:00
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
// 刘海屏适配器Ω
|
2025-08-14 12:35:19 +08:00
|
|
|
|
private UINotchScreenAdapter _notchScreenAdapter;
|
|
|
|
|
|
|
|
|
|
|
|
// GraphicRaycaster管理器
|
|
|
|
|
|
private GraphicRaycasterManager _graphicRaycasterManager;
|
2025-08-14 15:00:57 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Public accessor for the `GraphicRaycasterManager`. Lazily initializes on first access and cannot be assigned.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public GraphicRaycasterManager GraphicRaycasterManager
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_graphicRaycasterManager == null)
|
|
|
|
|
|
InitGraphicRaycasterManager();
|
|
|
|
|
|
return _graphicRaycasterManager;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-08-08 12:19:32 +08:00
|
|
|
|
|
2025-04-16 12:24:10 +08:00
|
|
|
|
public bool IsClosing; //正在关闭
|
2025-12-26 12:16:37 +08:00
|
|
|
|
|
2025-12-25 20:26:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 返回键策略(在窗口加载到Layer时设置)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public IUIBackStrategy BackStrategy { get; set; }
|
|
|
|
|
|
|
2024-08-12 19:31:50 +08:00
|
|
|
|
private bool _isPlayingOpenAnim;
|
|
|
|
|
|
|
2024-10-21 19:55:05 +08:00
|
|
|
|
protected Sequence _openAnimSeq;
|
2024-08-12 19:31:50 +08:00
|
|
|
|
public bool IsShowOpenAnim;
|
|
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
public string WindowName
|
|
|
|
|
|
{
|
|
|
|
|
|
set { mWindowName = value; }
|
|
|
|
|
|
get { return mWindowName; }
|
|
|
|
|
|
}
|
2023-11-21 13:31:06 +08:00
|
|
|
|
|
2023-08-22 19:08:45 +08:00
|
|
|
|
[HideInInspector]
|
2025-12-19 14:44:14 +08:00
|
|
|
|
public UICanvasLayer uiWindowLayer;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
[HideInInspector]
|
2025-09-09 20:26:41 +08:00
|
|
|
|
protected bool isInited = false;
|
2024-04-29 15:39:46 +08:00
|
|
|
|
|
2025-08-14 12:35:19 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化GraphicRaycaster管理器
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void InitGraphicRaycasterManager()
|
|
|
|
|
|
{
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (_graphicRaycasterManager == null && gameObject is not null)
|
2025-08-14 12:35:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
_graphicRaycasterManager = new GraphicRaycasterManager(gameObject);
|
2025-08-06 14:33:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-14 12:35:19 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化刘海屏适配
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void InitScreenAdaption()
|
2023-12-05 19:27:56 +08:00
|
|
|
|
{
|
2025-08-14 12:35:19 +08:00
|
|
|
|
if (_notchScreenAdapter == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_notchScreenAdapter = new UINotchScreenAdapter(transform);
|
|
|
|
|
|
}
|
2023-12-05 19:27:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-08 16:16:50 +08:00
|
|
|
|
public async UniTask<T> LoadAssetAsync<T>(string path) where T : UnityEngine.Object
|
2024-04-28 14:45:31 +08:00
|
|
|
|
{
|
2024-10-30 18:52:22 +08:00
|
|
|
|
if (gameObject)
|
2024-05-08 12:44:22 +08:00
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
// 确保资源管理器已初始化
|
|
|
|
|
|
if (_assetReferenceManager == null)
|
2024-10-30 18:52:22 +08:00
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
_assetReferenceManager = new PhxhSDK.AssetReferenceManager();
|
2024-10-30 18:52:22 +08:00
|
|
|
|
}
|
2025-09-03 18:19:04 +08:00
|
|
|
|
|
|
|
|
|
|
return await _assetReferenceManager.LoadAssetAsync<T>(path);
|
2024-04-28 14:45:31 +08:00
|
|
|
|
}
|
2024-10-30 18:52:22 +08:00
|
|
|
|
|
2025-09-03 18:19:04 +08:00
|
|
|
|
// 如果gameObject为空,直接通过AssetManager加载
|
|
|
|
|
|
return await AssetManager.Instance.LoadAssetAsync<T>(path);
|
2024-04-28 14:45:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-05-14 17:32:15 +08:00
|
|
|
|
/// <summary>
|
2025-09-09 20:26:41 +08:00
|
|
|
|
/// 异步预加载资源
|
2024-05-14 17:32:15 +08:00
|
|
|
|
/// </summary>
|
2025-09-09 20:26:41 +08:00
|
|
|
|
/// <param name="path">资源路径</param>
|
2024-05-14 17:32:15 +08:00
|
|
|
|
public async UniTask PostPreload<T>(string path) where T : UnityEngine.Object
|
|
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
// 确保资源管理器已初始化
|
|
|
|
|
|
if (_assetReferenceManager == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetReferenceManager = new PhxhSDK.AssetReferenceManager();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await _assetReferenceManager.PostPreload<T>(path);
|
2024-05-14 17:32:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-09 20:26:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取预加载的资源结果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="path">资源路径</param>
|
2024-05-14 17:32:15 +08:00
|
|
|
|
public T GetPreLoadResult<T>(string path) where T : UnityEngine.Object
|
|
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
// 优先使用资源管理器获取结果
|
|
|
|
|
|
if (_assetReferenceManager != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _assetReferenceManager.GetPreLoadResult<T>(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 回退到直接使用AssetManager
|
2024-05-14 17:32:15 +08:00
|
|
|
|
return AssetManager.Instance.GetPreLoadResult<T>(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-28 14:45:31 +08:00
|
|
|
|
protected void UnLoad()
|
|
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
// 使用资源管理器卸载所有资源
|
|
|
|
|
|
if (_assetReferenceManager != null)
|
2024-04-28 14:45:31 +08:00
|
|
|
|
{
|
2025-09-03 18:19:04 +08:00
|
|
|
|
_assetReferenceManager.UnloadAll();
|
2024-04-28 14:45:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-09 14:37:29 +08:00
|
|
|
|
|
2025-09-04 14:23:51 +08:00
|
|
|
|
#region Component Utilities
|
2023-08-22 19:08:45 +08:00
|
|
|
|
|
|
|
|
|
|
public GameObject FindObj(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObject obj = transform.Find(path)?.gameObject;
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (obj is null)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("{0}未找到 {1}/{2}", mWindowName, gameObject.name, path);
|
|
|
|
|
|
}
|
2023-08-22 19:08:45 +08:00
|
|
|
|
return obj;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-26 16:06:42 +08:00
|
|
|
|
public T GetComponent<T>(string path = "") where T : Behaviour
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2023-10-19 15:00:19 +08:00
|
|
|
|
var component = transform.Find(path)?.GetComponent<T>();
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (component is null)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("{0}未找到组件{1}: {2}", mWindowName, typeof(T).Name, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
return component;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|
2025-04-29 15:10:33 +08:00
|
|
|
|
|
|
|
|
|
|
public T AddComponent<T>(string path = "") where T : Behaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = transform.Find(path);
|
|
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
var component = trans.GetComponent<T>();
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (component is null)
|
2025-04-29 15:10:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
component = trans.gameObject.AddComponent<T>();
|
|
|
|
|
|
//DebugUtil.LogError("{0}未找到组件{1}: {2}", mWindowName, typeof(T).Name, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
return component;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DebugUtil.LogError("{0}未找到路径: {1}", mWindowName, path);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2024-01-24 15:42:01 +08:00
|
|
|
|
#endregion
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
#region State Query Methods
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsCreated()
|
2023-12-29 15:03:59 +08:00
|
|
|
|
{
|
2025-09-09 20:26:41 +08:00
|
|
|
|
return isInited;
|
2023-12-29 15:03:59 +08:00
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
public bool IsShow()
|
2023-08-22 19:08:45 +08:00
|
|
|
|
{
|
2025-09-04 12:16:08 +08:00
|
|
|
|
return _isShow;
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
public bool IsHide()
|
2024-04-07 12:53:01 +08:00
|
|
|
|
{
|
2025-09-04 12:16:08 +08:00
|
|
|
|
return !_isShow;
|
2024-04-07 12:53:01 +08:00
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
2026-01-06 16:45:21 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否处于活跃状态(显示且未暂停)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsActive()
|
|
|
|
|
|
{
|
|
|
|
|
|
return _isShow && !_isPaused;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否处于暂停状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsPaused()
|
|
|
|
|
|
{
|
|
|
|
|
|
return _isPaused;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Pause/Resume Management
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 暂停窗口(手动调用)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 功能:
|
|
|
|
|
|
/// - 标记窗口为暂停状态
|
|
|
|
|
|
/// - 调用 OnPause 回调
|
|
|
|
|
|
/// - 可选:隐藏渲染(通过 hideRendering 参数控制)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 使用场景:
|
|
|
|
|
|
/// - 游戏暂停时,手动暂停战斗 UI
|
|
|
|
|
|
/// - 弹出全屏广告时,暂停游戏主界面
|
|
|
|
|
|
/// - 特殊业务逻辑需要暂停某个窗口
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 示例:
|
|
|
|
|
|
/// battleUI.PauseWindow(hideRendering: false); // 暂停逻辑但保持显示
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="hideRendering">是否同时隐藏渲染(SetActive(false))</param>
|
|
|
|
|
|
public void PauseWindow(bool hideRendering = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 状态检查
|
|
|
|
|
|
if (!_isShow)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogWarning($"[UIWindow] PauseWindow failed: window is not showing ({WindowName})");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_isPaused)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogWarning($"[UIWindow] PauseWindow ignored: already paused ({WindowName})");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_isPaused = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 调用子类的暂停逻辑
|
|
|
|
|
|
OnPause();
|
|
|
|
|
|
|
|
|
|
|
|
// 可选:隐藏渲染
|
|
|
|
|
|
if (hideRendering && gameObject != null && gameObject.activeSelf)
|
|
|
|
|
|
{
|
|
|
|
|
|
gameObject.SetActive(false);
|
|
|
|
|
|
DebugUtil.Log($"[UIWindow] Paused (hidden): {WindowName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.Log($"[UIWindow] Paused (logic only): {WindowName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 恢复窗口(手动调用)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 功能:
|
|
|
|
|
|
/// - 标记窗口为活跃状态
|
|
|
|
|
|
/// - 调用 OnResume 回调
|
|
|
|
|
|
/// - 可选:显示渲染(通过 showRendering 参数控制)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 使用场景:
|
|
|
|
|
|
/// - 游戏恢复时,手动恢复战斗 UI
|
|
|
|
|
|
/// - 广告关闭后,恢复游戏主界面
|
|
|
|
|
|
/// - 特殊业务逻辑需要恢复某个窗口
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 示例:
|
|
|
|
|
|
/// battleUI.ResumeWindow(showRendering: true); // 恢复逻辑并显示
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="showRendering">是否同时显示渲染(SetActive(true))</param>
|
|
|
|
|
|
public void ResumeWindow(bool showRendering = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 状态检查
|
|
|
|
|
|
if (!_isShow)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogWarning($"[UIWindow] ResumeWindow failed: window is not showing ({WindowName})");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!_isPaused)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogWarning($"[UIWindow] ResumeWindow ignored: not paused ({WindowName})");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_isPaused = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 可选:显示渲染
|
|
|
|
|
|
if (showRendering && gameObject != null && !gameObject.activeSelf)
|
|
|
|
|
|
{
|
|
|
|
|
|
gameObject.SetActive(true);
|
|
|
|
|
|
DebugUtil.Log($"[UIWindow] Resumed (shown): {WindowName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.Log($"[UIWindow] Resumed (logic only): {WindowName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用子类的恢复逻辑
|
|
|
|
|
|
OnResume();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Virtual Methods - Pause/Resume
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 窗口暂停回调(子类重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 调用时机:手动调用 PauseWindow() 时
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 建议处理:
|
|
|
|
|
|
/// - 停止播放背景音乐/音效
|
|
|
|
|
|
/// - 暂停动画/粒子特效
|
|
|
|
|
|
/// - 暂停定时器/倒计时
|
|
|
|
|
|
/// - 暂停网络轮询(可选)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 示例:
|
|
|
|
|
|
/// <code>
|
|
|
|
|
|
/// protected override void OnPause()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// if (_bgmHandle != -1)
|
|
|
|
|
|
/// AudioManager.Instance.PauseBGM(_bgmHandle);
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// </code>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual void OnPause() { }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 窗口恢复回调(子类重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 调用时机:手动调用 ResumeWindow() 时
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 建议处理:
|
|
|
|
|
|
/// - 恢复播放背景音乐/音效
|
|
|
|
|
|
/// - 恢复动画/粒子特效
|
|
|
|
|
|
/// - 恢复定时器/倒计时
|
|
|
|
|
|
/// - 刷新数据(可选)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 示例:
|
|
|
|
|
|
/// <code>
|
|
|
|
|
|
/// protected override void OnResume()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// if (_bgmHandle != -1)
|
|
|
|
|
|
/// AudioManager.Instance.ResumeBGM(_bgmHandle);
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// </code>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual void OnResume() { }
|
|
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
#endregion
|
2023-08-22 19:08:45 +08:00
|
|
|
|
}
|