using UnityEngine; namespace BaseGames.Enemies { /// /// 角色身体碰撞体的唯一权威查询口。 /// 几何实时取自碰撞体 bounds(随位置/动画变化,不缓存数值),仅缓存碰撞体引用。 /// 唯一数据源见 ——其它组件不得自行解析身体碰撞体。 /// public interface IEnemyBody { Collider2D Collider { get; } /// 世界空间包围盒;实时查询。 Bounds Bounds { get; } float Width { get; } float Height { get; } float HalfWidth { get; } float HalfHeight { get; } Vector2 Center { get; } /// 脚底中点 (center.x, min.y)。 Vector2 FootPoint { get; } /// 的前缘 X(dir≥0 取 max.x,否则 min.x)。 float FrontEdgeX(float dir); /// 的后缘 X(前缘的相反侧)。 float RearEdgeX(float dir); /// /// 身体是否已**整体**越过世界 X 坐标: /// dir≥0 时后缘(min.x) ≥ worldX;dir<0 时后缘(max.x) ≤ worldX。 /// bool HasPassed(float worldX, float dir); } /// /// 的实现(纯 C# 类,非 MonoBehaviour)。 /// 懒解析碰撞体 → 编辑器模式(Gizmo / OnValidate,Awake 未执行)同样可用。 /// public sealed class EnemyBody : IEnemyBody { private readonly GameObject _owner; private readonly Collider2D _explicitCollider; private Collider2D _resolved; /// 宿主 GameObject(未显式指定碰撞体时从其上取 Collider2D)。 /// 显式指定的身体碰撞体;可为 null。 public EnemyBody(GameObject owner, Collider2D explicitCollider) { _owner = owner; _explicitCollider = explicitCollider; } public Collider2D Collider { get { if (_explicitCollider != null) return _explicitCollider; if (_resolved == null && _owner != null) _resolved = _owner.GetComponent(); return _resolved; } } /// /// 碰撞体缺失时返回以宿主位置为中心的零尺寸包围盒。 /// 该错误已由 在 Awake/OnValidate 显式报出,此处不重复每帧刷屏。 /// public Bounds Bounds { get { var col = Collider; if (col != null) return col.bounds; return new Bounds(_owner != null ? _owner.transform.position : Vector3.zero, Vector3.zero); } } public float Width => Bounds.size.x; public float Height => Bounds.size.y; public float HalfWidth => Bounds.extents.x; public float HalfHeight => Bounds.extents.y; public Vector2 Center => Bounds.center; public Vector2 FootPoint { get { var b = Bounds; return new Vector2(b.center.x, b.min.y); } } public float FrontEdgeX(float dir) { var b = Bounds; return FrontEdge(b.min.x, b.max.x, dir); } public float RearEdgeX (float dir) { var b = Bounds; return RearEdge (b.min.x, b.max.x, dir); } public bool HasPassed(float worldX, float dir) { var b = Bounds; return BodyPassed(b.min.x, b.max.x, worldX, dir); } // ── 方向纯函数(static,便于无场景依赖单测;符号最易写反,集中于此)────── public static float FrontEdge(float minX, float maxX, float dir) => dir >= 0f ? maxX : minX; public static float RearEdge (float minX, float maxX, float dir) => dir >= 0f ? minX : maxX; public static bool BodyPassed(float minX, float maxX, float worldX, float dir) => dir >= 0f ? minX >= worldX : maxX <= worldX; } }