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 到点停顿状态
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;