using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using XericLibrary.Runtime.MacroLibrary;
using System;
namespace XericUI.VisualForm
{
///
/// 锚点坞 - 挂载在Canvas上的主要布局组件管理器。
/// 负责收集所有世界锚点,每帧将世界坐标转换到屏幕坐标,并管理中间窗口状态。
///
[AddComponentMenu("Xeric UI Vessel/AnchorWindow/AnchorDock")]
[DefaultExecutionOrder(31000)]
public class AnchorDock : MonoBehaviour
{
[Header("配置")]
[SerializeField, Tooltip("指定摄像机,不填则自动检测")]
private Camera m_OverrideCamera;
[SerializeField, Tooltip("坐标变化阈值,移动超过此值才会标记坐标脏")]
private float m_PositionThreshold = 0.1f;
[Space]
[SerializeField, Tooltip("预注册的锚点列表(坞可直接标记要使用的窗口锚点,双方引用有一个可不填)")]
private List m_TargetAnchors = new List();
[SerializeField, Tooltip("预分配的中间类对象池容量")]
private int m_StatePoolPreallocate = 16;
[Header("安全区")]
[SerializeField, Tooltip("安全区矩形(Canvas本地空间),窗口超出此区域视为超出安全区")]
private Rect m_SafeZone = new Rect(.1f, .05f, .8f, .8f);
[SerializeField, Tooltip("安全区检测模式")]
private SafeZoneMode m_SafeZoneMode = SafeZoneMode.Rect;
[SerializeField, Tooltip("安全区坐标单位")]
private SafeZoneUnit m_SafeZoneUnit = SafeZoneUnit.Ratio;
#region 静态单例
private static AnchorDock s_Main;
///
/// 主要的静态单例锚点坞引用
///
public static AnchorDock Main => s_Main;
///
/// 待注册锚点列表 — 锚点在OnEnable时找不到坞,将自己暂存于此,等待坞后续处理
///
internal static readonly HashSet s_PendingAnchors = new HashSet();
#endregion
#region 内部状态
private Canvas _canvas;
private Camera _worldCamera;
private Camera _uiCamera;
private RectTransform _rectTransform;
///
/// 锚点集合(HashSet用于O(1)去重和查找)
///
private readonly HashSet _anchorSet = new HashSet();
///
/// 锚点脏标记 - 有新增或移除时为true,延迟到下一帧处理
///
private bool _anchorsDirty;
///
/// 待新增锚点列表(脏更新期间收集)
///
private readonly List _pendingAdds = new List();
///
/// 待移除锚点列表(脏更新期间收集)
///
private readonly List _pendingRemoves = new List();
///
/// 活跃的窗口状态字典:锚点 -> 中间窗口状态类
///
private readonly Dictionary _activeStates = new Dictionary();
///
/// 中间类对象池
///
private readonly Queue _statePool = new Queue();
///
/// 子对象哈希集 - 用于O(1)快速检查对象是否在子项中
///
private readonly HashSet _childrenHashSet = new HashSet();
///
/// 子对象哈希集脏标记
///
private bool _childrenSetDirty = true;
///
/// 摄像机变换脏标记
///
private bool _cameraDirty;
///
/// 子类可读的摄像机脏标记
///
protected bool IsCameraDirty => _cameraDirty;
///
/// 上帧世界摄像机坐标
///
private Vector3 _lastWorldCameraPosition;
///
/// 上帧世界摄像机旋转
///
private Quaternion _lastWorldCameraRotation;
///
/// 上帧UI摄像机坐标
///
private Vector3 _lastUICameraPosition;
///
/// 上帧UI摄像机旋转
///
private Quaternion _lastUICameraRotation;
#endregion
#region 子类可访问属性
///
/// 活跃的窗口状态字典(供子类如AdvancedAnchorDock进行碰撞计算)
///
protected Dictionary ActiveStates => _activeStates;
///
/// Canvas本地空间Rect(供子类获取安全区等)
///
protected Rect CanvasLocalRect => ((RectTransform)_canvas.transform).rect;
///
/// 像素安全区
///
protected Rect PixelSafeZone
{
get
{
if (_canvas == null) return Rect.zero;
return m_SafeZoneUnit == SafeZoneUnit.Ratio
? RatioSafeZoneToPixel(m_SafeZone, CanvasLocalRect)
: m_SafeZone;
}
}
#endregion
#region 公开属性
///
/// 世界摄像机(用于 World→Screen 转换,通常是 MainCamera)
///
public Camera WorldCamera => _worldCamera;
///
/// UI摄像机(用于 Screen→Canvas 转换,Overlay时为null,Camera时为canvas.worldCamera)
///
public Camera UICamera => _uiCamera;
///
/// Canvas组件引用
///
public Canvas Canvas => _canvas;
///
/// RectTransform引用
///
public RectTransform RectTransform
{
get
{
if (_rectTransform == null)
_rectTransform = GetComponent();
return _rectTransform;
}
}
///
/// 坐标变化阈值
///
public float PositionThreshold => m_PositionThreshold;
#endregion
#region 生命周期
protected virtual void Awake()
{
// 在Awake阶段注册单例
s_Main = this;
}
protected virtual void OnEnable()
{
_canvas = GetComponentInParent