Files
zeling_v2/Assets/_Game/Scripts/Enemies/EnemyPatrolZone.cs
Joywayer 06048c966a feat: Add HurtBoxOwnerGuard to prevent multiple damage registrations from the same HitBox activation
- 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.
2026-06-02 16:10:44 +08:00

129 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
}