feat(enemy): Waypoints 受阻/到达即结算推进,删除对不可达点的无限重发

This commit is contained in:
2026-07-23 17:09:06 +08:00
parent 49b7adbdae
commit 8e71b1a922
@@ -44,6 +44,9 @@ namespace BaseGames.Enemies
// Wander 到点停顿状态 // Wander 到点停顿状态
private bool _wanderPausing; private bool _wanderPausing;
private float _wanderPauseTimer; private float _wanderPauseTimer;
// Waypoints 受阻结算停顿状态
private bool _wpPausing;
private float _wpPauseTimer;
public LocomotionMode CurrentMode => _mode; public LocomotionMode CurrentMode => _mode;
public bool IsMoving => _enemy != null && _enemy.Nav != null && _enemy.Nav.IsMoving; public bool IsMoving => _enemy != null && _enemy.Nav != null && _enemy.Nav.IsMoving;
@@ -61,6 +64,7 @@ namespace BaseGames.Enemies
if (_mode == mode) return; if (_mode == mode) return;
_mode = mode; _mode = mode;
_wanderPausing = false; // 切换模式清 Wander 停顿态 _wanderPausing = false; // 切换模式清 Wander 停顿态
_wpPausing = false; // 同时清 Waypoints 受阻停顿态
if (mode == LocomotionMode.Idle) _enemy?.StopMovement(); if (mode == LocomotionMode.Idle) _enemy?.StopMovement();
if (mode == LocomotionMode.Patrol && _enemy?.Stats != null) if (mode == LocomotionMode.Patrol && _enemy?.Stats != null)
_enemy.Nav?.SetSpeed(_enemy.Stats.WalkSpeed); _enemy.Nav?.SetSpeed(_enemy.Stats.WalkSpeed);
@@ -194,21 +198,37 @@ namespace BaseGames.Enemies
} }
break; break;
} }
// 到达判定对"吸附后的可达点"做,而非原始路点:原始路点可能摆在空中/崖外,
// 与之的距离永远进不了到达半径 → 卡死;吸附点是身体站得住的可达点。 var nav = _enemy.Nav;
// 到达判定对"吸附后的可达点"做(原始路点可能摆在空中/崖外,永远进不了到达半径)。
bool wpArrived = _wpIndex >= 0 && bool wpArrived = _wpIndex >= 0 &&
Vector2.Distance(_enemy.transform.position, _wpResolvedGoal) <= _waypointArriveRadius; 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(); AdvanceWaypoint();
SetWaypointGoal(); SetWaypointGoal();
} }
else if (_enemy.Nav != null && !_enemy.Nav.IsMoving) else if (nav != null && !nav.IsMoving && !nav.LastMoveObstructed)
{ {
// 有目标但 nav 空闲且未到达:初始寻路未成(如刚出生尚未映射到导航图那一帧的 MoveTo 失败) // 瞬态:刚出生尚未映射那一帧的 MoveTo 失败 → 重发(RequestMoveTo 自带 0.25s 防抖)。
// 或路径中途丢失 → 重发同一目标恢复。只重发、不推进索引;RequestMoveTo 自带 0.25s 防抖, // 仅"未受阻"时重发;受阻由上面 obstructedSettled 分支结算,不再无限重发不可达点。
// 寻路跨帧计算期间的重发会被防抖吞掉,不会每帧重启寻路。
_enemy.MoveTo(_wpResolvedGoal); _enemy.MoveTo(_wpResolvedGoal);
} }
break; break;