feat(enemy): 感知系统新增 BoxLOS 槽位(横向矩形视野+遮挡)
BoxCast 是纯几何矩形无遮挡,BatchLOS/Sight 有遮挡但为圆形。 新增 BoxLOS 槽位:OverlapBox 矩形区域 + 从感知原点多点 LOS 遮挡校验, 用于走廊/平台等横向矩形视野带遮挡的场景。 - enum 末尾追加 BoxLOS(避免打乱既有序列化索引) - 复用 boxSize/boxOffset 定义矩形、losBlockMask/losRayCount/losMinVisibility 定义遮挡 - 方向由 boxOffset.x 控制:0=前后双向对称,boxSize.x*0.5=仅前向 - Editor 补 Gizmo(矩形+眼点+实时检测连线)与条件字段 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ namespace BaseGames.Enemies.Perception
|
||||
{
|
||||
/// <summary>
|
||||
/// 敌人感知系统(自研纯物理实现,商业级设计)。
|
||||
/// 每个 <see cref="PerceptionSlot"/> 独立配置并独立运行,支持七种检测模式:
|
||||
/// 每个 <see cref="PerceptionSlot"/> 独立配置并独立运行,支持八种检测模式:
|
||||
/// • <b>RangeCircle</b> — OverlapCircle 纯几何范围检测(无遮挡)
|
||||
/// • <b>BatchLOS</b> — OverlapCircle + 单次 Raycast 自研批量视线检测(低开销,有帧延迟)
|
||||
/// • <b>FanCast</b> — OverlapCircle + 角度过滤扇形视野(纯几何,无遮挡)
|
||||
@@ -14,6 +14,7 @@ namespace BaseGames.Enemies.Perception
|
||||
/// • <b>Sight</b> — OverlapCircle + 可选扇形角度 + 强制多点 LOS 遮挡(专用视线传感器)
|
||||
/// • <b>RayCast</b> — 单/多根方向射线传感器,支持扩散角和遮挡层
|
||||
/// • <b>TriggerZone</b> — 物理触发器事件驱动(子节点 PerceptionTriggerProxy,零轮询)
|
||||
/// • <b>BoxLOS</b> — OverlapBox 矩形(横向)区域 + 多点 LOS 遮挡(矩形视野带遮挡)
|
||||
///
|
||||
/// <b>遮挡检测设计原则:</b>
|
||||
/// RangeCircle / FanCast / BoxCast 是纯几何传感器,不做遮挡校验。
|
||||
@@ -48,6 +49,8 @@ namespace BaseGames.Enemies.Perception
|
||||
RayCast,
|
||||
/// <summary>物理触发器事件驱动,依赖子节点 PerceptionTriggerProxy(零轮询开销)</summary>
|
||||
TriggerZone,
|
||||
/// <summary>OverlapBox 矩形(横向)区域 + 多点 LOS 遮挡校验(矩形视野带遮挡)</summary>
|
||||
BoxLOS,
|
||||
}
|
||||
|
||||
// ── 槽位定义 ──────────────────────────────────────────────────────────
|
||||
@@ -98,23 +101,23 @@ namespace BaseGames.Enemies.Perception
|
||||
|
||||
// ── BoxCast ────────────────────────────────────────────────────
|
||||
|
||||
[Tooltip("BoxCast:检测框尺寸 (宽, 高),单位米")]
|
||||
[Tooltip("BoxCast / BoxLOS:检测框尺寸 (宽, 高),单位米")]
|
||||
public Vector2 boxSize;
|
||||
|
||||
[Tooltip("BoxCast:相对于感知中心的偏移,X 分量随 localScale.x 自动翻转")]
|
||||
[Tooltip("BoxCast / BoxLOS:相对于感知中心的偏移,X 分量随 localScale.x 自动翻转。\n仅前向视野:X 设为 boxSize.x * 0.5(矩形整块推到前方);前后双向:X 设为 0(对称)。")]
|
||||
public Vector2 boxOffset;
|
||||
|
||||
// ── Sight LOS(仅 Sight 类型使用)────────────────────────────
|
||||
// ── LOS(Sight / BoxLOS 共用)────────────────────────────────
|
||||
|
||||
[Tooltip("[Sight 专用] 视线遮挡检测层(通常为 Platform + Wall + Ground)。\n⚠ 留 0 时视线始终通过(losBlockMask = 0 = 无遮挡层)。")]
|
||||
[Tooltip("[Sight / BoxLOS] 视线遮挡检测层(通常为 Platform + Wall + Ground)。\n⚠ 留 0 时视线始终通过(losBlockMask = 0 = 无遮挡层)。")]
|
||||
public LayerMask losBlockMask;
|
||||
|
||||
[Range(1, 5)]
|
||||
[Tooltip("[Sight 专用] LOS 多点采样数量:\n1 = 包围盒中心(最快)\n3 = 中心 + 上 + 下(推荐)\n5 = 中心 + 上下左右(最稳健)")]
|
||||
[Tooltip("[Sight / BoxLOS] LOS 多点采样数量:\n1 = 包围盒中心(最快)\n3 = 中心 + 上 + 下(推荐)\n5 = 中心 + 上下左右(最稳健)")]
|
||||
public int losRayCount;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
[Tooltip("[Sight 专用] 可见度阈值(0–1):\n0 = 任意 1 条通过即可(宽松)\n0.5 = 50% 通过\n1 = 全部通过(严格)")]
|
||||
[Tooltip("[Sight / BoxLOS] 可见度阈值(0–1):\n0 = 任意 1 条通过即可(宽松)\n0.5 = 50% 通过\n1 = 全部通过(严格)")]
|
||||
public float losMinVisibility;
|
||||
|
||||
// ── RayCast ───────────────────────────────────────────────────
|
||||
@@ -274,6 +277,7 @@ namespace BaseGames.Enemies.Perception
|
||||
case SlotType.BoxCast: RefreshBoxCast(ref slot, list); break;
|
||||
case SlotType.Sight: RefreshSight(ref slot, list); break;
|
||||
case SlotType.RayCast: RefreshRayCast(ref slot, list); break;
|
||||
case SlotType.BoxLOS: RefreshBoxLOS(ref slot, list); break;
|
||||
}
|
||||
|
||||
FireDiffEvents(slot.slotName);
|
||||
@@ -380,6 +384,34 @@ namespace BaseGames.Enemies.Perception
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 矩形视线传感器:OverlapBox(横向矩形区域)+ 多点 LOS 遮挡校验。
|
||||
/// 形状同 <see cref="SlotType.BoxCast"/>,但对每个候选目标从感知原点做遮挡射线,
|
||||
/// 用于"横向矩形视野带遮挡"的场景(如走廊 / 平台横向警戒)。
|
||||
/// <para>矩形以 <see cref="PerceptionSlot.boxSize"/> / <see cref="PerceptionSlot.boxOffset"/> 定义;
|
||||
/// 遮挡复用 <see cref="PerceptionSlot.losBlockMask"/> / losRayCount / losMinVisibility。
|
||||
/// losBlockMask = 0 时视线始终通过(退化为纯几何 BoxCast)。</para>
|
||||
/// </summary>
|
||||
private void RefreshBoxLOS(ref PerceptionSlot slot, List<GameObject> list)
|
||||
{
|
||||
if (slot.boxSize.x <= 0f || slot.boxSize.y <= 0f || slot.detectLayer == 0) return;
|
||||
|
||||
float facingSign = transform.localScale.x < 0f ? -1f : 1f;
|
||||
Vector2 origin = (Vector2)transform.position + new Vector2(slot.offset.x * facingSign, slot.offset.y);
|
||||
Vector2 center = origin + new Vector2(slot.boxOffset.x * facingSign, slot.boxOffset.y);
|
||||
|
||||
int count = Physics2D.OverlapBoxNonAlloc(center, slot.boxSize, 0f, _overlapBuffer, slot.detectLayer);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var col = _overlapBuffer[i];
|
||||
if (col == null) continue;
|
||||
// 遮挡校验:从感知原点(眼点)到目标;losBlockMask = 0 时始终通过
|
||||
if (!HasLineOfSight(origin, col.gameObject,
|
||||
slot.losBlockMask, Mathf.Max(1, slot.losRayCount), slot.losMinVisibility)) continue;
|
||||
if (!list.Contains(col.gameObject)) list.Add(col.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 视线传感器:OverlapCircle + 可选扇形角度过滤 + 强制多点 LOS 遮挡校验。
|
||||
/// 唯一内置遮挡检测的轮询槽位类型。
|
||||
|
||||
Reference in New Issue
Block a user