diff --git a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs index e0e7243e..80f3fe73 100644 --- a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs +++ b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs @@ -11,15 +11,23 @@ namespace BaseGames.Enemies [DisallowMultipleComponent] public sealed class EnemyLocomotion : MonoBehaviour, IEnemyLocomotion { - [Header("巡逻策略(P6 实现 Pace/Waypoints;当前仅 Wander)")] + [Header("巡逻策略(Wander/Pace/Waypoints)")] [SerializeField] private PatrolStrategy _patrolStrategy = PatrolStrategy.Wander; + [Header("Waypoints 策略参数")] + [SerializeField] private Transform[] _waypoints; + [SerializeField] private bool _pingPong; + private EnemyBase _enemy; private LocomotionMode _mode = LocomotionMode.Idle; private Transform _approachTarget; private Vector2 _facePoint; private LocomotionMode _gaitMode; private bool _gaitInit; + private float _paceDir = 1f; + private int _wpIndex = -1; + private int _wpDir = 1; + private bool _warnedNoWaypoints; public LocomotionMode CurrentMode => _mode; public bool IsMoving => _enemy != null && _enemy.Nav != null && _enemy.Nav.IsMoving; @@ -96,17 +104,48 @@ namespace BaseGames.Enemies private void TickPatrol() { - var nav = _enemy.Nav; - if (nav == null) return; switch (_patrolStrategy) { case PatrolStrategy.Wander: - if (!nav.IsMoving) nav.WalkToRandom(); + if (_enemy.Nav != null && !_enemy.Nav.IsMoving) _enemy.Nav.WalkToRandom(); break; - // Pace / Waypoints:P6 实现 - default: - if (!nav.IsMoving) nav.WalkToRandom(); + + case PatrolStrategy.Pace: // 撞墙/悬崖翻向的来回踱步(速度驱动,不依赖 nav) + var mv = _enemy.Movement; + if (mv != null && (mv.IsWallAhead || mv.IsLedgeAhead)) _paceDir = -_paceDir; + _enemy.MoveInDirection(_paceDir); break; + + case PatrolStrategy.Waypoints: // 按序(loop 或 ping-pong)巡逻路点 + if (_waypoints == null || _waypoints.Length == 0) + { + if (!_warnedNoWaypoints) + { + Debug.LogWarning("[EnemyLocomotion] PatrolStrategy=Waypoints 但未配置 _waypoints,无法巡逻。", this); + _warnedNoWaypoints = true; + } + break; + } + if (_enemy.Nav != null && !_enemy.Nav.IsMoving) + { + AdvanceWaypoint(); + _enemy.MoveTo(_waypoints[_wpIndex].position); + } + break; + } + } + + private void AdvanceWaypoint() + { + if (_pingPong) + { + int next = _wpIndex + _wpDir; + if (next < 0 || next >= _waypoints.Length) { _wpDir = -_wpDir; next = _wpIndex + _wpDir; } + _wpIndex = Mathf.Clamp(next, 0, _waypoints.Length - 1); + } + else + { + _wpIndex = (_wpIndex + 1) % _waypoints.Length; } } }