- Implemented HurtBoxOwnerGuard to ensure that multiple HurtBoxes on the same character do not register damage multiple times during a single HitBox activation. - Added custom editor for HitBox to facilitate the creation of shape colliders with HitBoxColliderProxy. - Introduced PhysicsPerceptionSystem for enemy perception, supporting multiple detection modes including RangeCircle, BatchLOS, FanCast, and BoxCast. - Created EnemyPatrolZone to define patrol and chase areas for enemies, allowing for shared zones among multiple enemies. - Added BD_IsOutsideZone conditional task for Behavior Designer to check if an enemy or player is outside a defined patrol zone.
129 lines
5.7 KiB
C#
129 lines
5.7 KiB
C#
using UnityEngine;
|
||
|
||
namespace BaseGames.Enemies
|
||
{
|
||
/// <summary>
|
||
/// 地图固定巡逻/追击区域(矩形)。
|
||
///
|
||
/// 放置于场景中(非敌人子节点),通过 EnemyBase Inspector 的 _patrolZone 字段引用。
|
||
/// 同一区域可被多个敌人共享(哨兵组、竞技场等)。
|
||
///
|
||
/// 区域层级:
|
||
/// <list type="bullet">
|
||
/// <item><b>巡逻区域(Patrol)</b>:绿色矩形,巡逻点限制范围。</item>
|
||
/// <item><b>追击区域(Chase)</b>:橙色矩形 = 巡逻区域 + <see cref="ChaseExpandPadding"/>;
|
||
/// 玩家进入/出此区域触发追击开始/放弃。</item>
|
||
/// </list>
|
||
/// </summary>
|
||
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;
|
||
|
||
// ── 计算属性 ──────────────────────────────────────────────────────
|
||
|
||
/// <summary>巡逻区域中心(世界坐标)。</summary>
|
||
public Vector2 PatrolCenter => (Vector2)transform.position + PatrolOffset;
|
||
|
||
/// <summary>追击区域中心与巡逻区域共享。</summary>
|
||
public Vector2 ChaseCenter => PatrolCenter;
|
||
|
||
/// <summary>有效追击区域尺寸:自定义 > 0 时使用自定义,否则巡逻区域 + 边距。</summary>
|
||
public Vector2 EffectiveChaseSize
|
||
{
|
||
get
|
||
{
|
||
if (CustomChaseSize.sqrMagnitude > 0f) return CustomChaseSize;
|
||
return PatrolSize + Vector2.one * (ChaseExpandPadding * 2f);
|
||
}
|
||
}
|
||
|
||
// ── 空间查询 ──────────────────────────────────────────────────────
|
||
|
||
/// <summary>判断世界坐标 <paramref name="worldPos"/> 是否在巡逻区域内。</summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>判断世界坐标 <paramref name="worldPos"/> 是否在追击区域内。</summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>将 <paramref name="worldPos"/> 夹紧到巡逻区域内最近点(用于归位目标)。</summary>
|
||
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
|
||
}
|
||
}
|