diff --git a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs index aedaca57..7b15f806 100644 --- a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs +++ b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs @@ -44,6 +44,9 @@ namespace BaseGames.Enemies // Wander 到点停顿状态 private bool _wanderPausing; private float _wanderPauseTimer; + // Waypoints 受阻结算停顿状态 + private bool _wpPausing; + private float _wpPauseTimer; public LocomotionMode CurrentMode => _mode; public bool IsMoving => _enemy != null && _enemy.Nav != null && _enemy.Nav.IsMoving; @@ -61,6 +64,7 @@ namespace BaseGames.Enemies if (_mode == mode) return; _mode = mode; _wanderPausing = false; // 切换模式清 Wander 停顿态 + _wpPausing = false; // 同时清 Waypoints 受阻停顿态 if (mode == LocomotionMode.Idle) _enemy?.StopMovement(); if (mode == LocomotionMode.Patrol && _enemy?.Stats != null) _enemy.Nav?.SetSpeed(_enemy.Stats.WalkSpeed); @@ -194,21 +198,37 @@ namespace BaseGames.Enemies } break; } - // 到达判定对"吸附后的可达点"做,而非原始路点:原始路点可能摆在空中/崖外, - // 与之的距离永远进不了到达半径 → 卡死;吸附点是身体站得住的可达点。 + + var nav = _enemy.Nav; + + // 到达判定对"吸附后的可达点"做(原始路点可能摆在空中/崖外,永远进不了到达半径)。 bool wpArrived = _wpIndex >= 0 && Vector2.Distance(_enemy.transform.position, _wpResolvedGoal) <= _waypointArriveRadius; - if (_wpIndex < 0 || wpArrived) + + // 受阻结算:执行层已把敌人带到最近可达点并停下(或原地停) → 视为本路点完成。 + bool obstructedSettled = nav != null && nav.LastMoveObstructed && !nav.IsMoving; + + if (_wpIndex < 0 || wpArrived || obstructedSettled) { - // 首次 / 到达当前路点 → 推进到下一路点并寻路 + // 受阻结算走短暂停顿(复用 Wander 停顿参数);正常到达/首个点立即推进。 + if (obstructedSettled && !_wpPausing) + { + _wpPausing = true; + _wpPauseTimer = Random.Range(_wanderPauseMin, Mathf.Max(_wanderPauseMin, _wanderPauseMax)); + } + if (_wpPausing) + { + _wpPauseTimer -= Time.deltaTime; + if (_wpPauseTimer > 0f) break; // 停顿中,原地待机 + _wpPausing = false; + } AdvanceWaypoint(); SetWaypointGoal(); } - else if (_enemy.Nav != null && !_enemy.Nav.IsMoving) + else if (nav != null && !nav.IsMoving && !nav.LastMoveObstructed) { - // 有目标但 nav 空闲且未到达:初始寻路未成(如刚出生、尚未映射到导航图那一帧发的 MoveTo 失败) - // 或路径中途丢失 → 重发同一目标恢复。只重发、不推进索引;RequestMoveTo 自带 0.25s 防抖, - // 寻路跨帧计算期间的重发会被防抖吞掉,不会每帧重启寻路。 + // 瞬态:刚出生尚未映射那一帧的 MoveTo 失败 → 重发(RequestMoveTo 自带 0.25s 防抖)。 + // 仅"未受阻"时重发;受阻由上面 obstructedSettled 分支结算,不再无限重发不可达点。 _enemy.MoveTo(_wpResolvedGoal); } break;