using UnityEngine; namespace BaseGames.Enemies { /// /// 地图固定巡逻/追击区域(矩形)。 /// /// 放置于场景中(非敌人子节点),通过 EnemyBase Inspector 的 _patrolZone 字段引用。 /// 同一区域可被多个敌人共享(哨兵组、竞技场等)。 /// /// 区域层级: /// /// 巡逻区域(Patrol):绿色矩形,巡逻点限制范围。 /// 追击区域(Chase):橙色矩形 = 巡逻区域 + ; /// 玩家进入/出此区域触发追击开始/放弃。 /// /// public class EnemyPatrolZone : MonoBehaviour { [Header("巡逻区域")] [Tooltip("巡逻区域中心相对 transform.position 的偏移(局部偏移,方便在 Scene 中移动节点)")] public Vector2 PatrolOffset = Vector2.zero; [Tooltip("巡逻区域尺寸(宽 × 高,单位 m)")] public Vector2 PatrolSize = new Vector2(10f, 4f); [Header("追击区域")] [Tooltip("追击区域向四周扩展的边距(m);追击区域 = 巡逻区域各边 + 此值。0 = 不扩展(追击 = 巡逻)")] [Min(0f)] public float ChaseExpandPadding = 8f; [Tooltip("自定义追击区域尺寸(宽×高);保持 Vector2.zero 时使用巡逻区域 + ChaseExpandPadding 自动计算")] public Vector2 CustomChaseSize = Vector2.zero; // ── 计算属性 ────────────────────────────────────────────────────── /// 巡逻区域中心(世界坐标)。 public Vector2 PatrolCenter => (Vector2)transform.position + PatrolOffset; /// 追击区域中心与巡逻区域共享。 public Vector2 ChaseCenter => PatrolCenter; /// 有效追击区域尺寸:自定义 > 0 时使用自定义,否则巡逻区域 + 边距。 public Vector2 EffectiveChaseSize { get { if (CustomChaseSize.sqrMagnitude > 0f) return CustomChaseSize; return PatrolSize + Vector2.one * (ChaseExpandPadding * 2f); } } // ── 空间查询 ────────────────────────────────────────────────────── /// 判断世界坐标 是否在巡逻区域内。 public bool ContainsPatrol(Vector2 worldPos) { Vector2 delta = worldPos - PatrolCenter; Vector2 half = PatrolSize * 0.5f; return Mathf.Abs(delta.x) <= half.x && Mathf.Abs(delta.y) <= half.y; } /// 判断世界坐标 是否在追击区域内。 public bool ContainsChase(Vector2 worldPos) { Vector2 delta = worldPos - ChaseCenter; Vector2 half = EffectiveChaseSize * 0.5f; return Mathf.Abs(delta.x) <= half.x && Mathf.Abs(delta.y) <= half.y; } /// 夹紧到巡逻区域内最近点(用于归位目标)。 public Vector2 ClampToPatrol(Vector2 worldPos) { Vector2 center = PatrolCenter; Vector2 half = PatrolSize * 0.5f; return new Vector2( Mathf.Clamp(worldPos.x, center.x - half.x, center.x + half.x), Mathf.Clamp(worldPos.y, center.y - half.y, center.y + half.y) ); } // ── Gizmos ──────────────────────────────────────────────────────── #if UNITY_EDITOR private void OnDrawGizmos() { Vector2 patrol = PatrolCenter; Vector2 chase = ChaseCenter; // 追击区域(橙色,后绘,垫在巡逻区域下方) Vector2 chaseSize = EffectiveChaseSize; Gizmos.color = new Color(1f, 0.55f, 0.1f, 0.07f); Gizmos.DrawCube(chase, chaseSize); Gizmos.color = new Color(1f, 0.55f, 0.1f, 0.7f); Gizmos.DrawWireCube(chase, chaseSize); // 巡逻区域(绿色,前绘,覆盖在追击区域上方) Gizmos.color = new Color(0.2f, 0.9f, 0.2f, 0.12f); Gizmos.DrawCube(patrol, PatrolSize); Gizmos.color = new Color(0.2f, 0.9f, 0.2f, 0.85f); Gizmos.DrawWireCube(patrol, PatrolSize); // 中心点 Gizmos.color = new Color(0.2f, 0.9f, 0.2f, 1f); Gizmos.DrawSphere(patrol, 0.15f); } private void OnDrawGizmosSelected() { // 选中时用更鲜艳的线框突出显示 Vector2 patrol = PatrolCenter; Gizmos.color = Color.green; Gizmos.DrawWireCube(patrol, PatrolSize); Gizmos.color = new Color(1f, 0.7f, 0f); Gizmos.DrawWireCube(ChaseCenter, EffectiveChaseSize); // 标注尺寸(仅在 Selected 时绘制) UnityEditor.Handles.color = Color.green; UnityEditor.Handles.Label(patrol + Vector2.right * PatrolSize.x * 0.5f, $"Patrol {PatrolSize.x:F1}×{PatrolSize.y:F1}"); UnityEditor.Handles.color = new Color(1f, 0.7f, 0f); Vector2 cs = EffectiveChaseSize; UnityEditor.Handles.Label(ChaseCenter + Vector2.right * cs.x * 0.5f, $"Chase {cs.x:F1}×{cs.y:F1}"); } #endif } }