feat(enemy): EnemyLocomotion 巡逻策略 Pace(踱步) + Waypoints(路点 loop/ping-pong)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,15 +11,23 @@ namespace BaseGames.Enemies
|
|||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public sealed class EnemyLocomotion : MonoBehaviour, IEnemyLocomotion
|
public sealed class EnemyLocomotion : MonoBehaviour, IEnemyLocomotion
|
||||||
{
|
{
|
||||||
[Header("巡逻策略(P6 实现 Pace/Waypoints;当前仅 Wander)")]
|
[Header("巡逻策略(Wander/Pace/Waypoints)")]
|
||||||
[SerializeField] private PatrolStrategy _patrolStrategy = PatrolStrategy.Wander;
|
[SerializeField] private PatrolStrategy _patrolStrategy = PatrolStrategy.Wander;
|
||||||
|
|
||||||
|
[Header("Waypoints 策略参数")]
|
||||||
|
[SerializeField] private Transform[] _waypoints;
|
||||||
|
[SerializeField] private bool _pingPong;
|
||||||
|
|
||||||
private EnemyBase _enemy;
|
private EnemyBase _enemy;
|
||||||
private LocomotionMode _mode = LocomotionMode.Idle;
|
private LocomotionMode _mode = LocomotionMode.Idle;
|
||||||
private Transform _approachTarget;
|
private Transform _approachTarget;
|
||||||
private Vector2 _facePoint;
|
private Vector2 _facePoint;
|
||||||
private LocomotionMode _gaitMode;
|
private LocomotionMode _gaitMode;
|
||||||
private bool _gaitInit;
|
private bool _gaitInit;
|
||||||
|
private float _paceDir = 1f;
|
||||||
|
private int _wpIndex = -1;
|
||||||
|
private int _wpDir = 1;
|
||||||
|
private bool _warnedNoWaypoints;
|
||||||
|
|
||||||
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;
|
||||||
@@ -96,17 +104,48 @@ namespace BaseGames.Enemies
|
|||||||
|
|
||||||
private void TickPatrol()
|
private void TickPatrol()
|
||||||
{
|
{
|
||||||
var nav = _enemy.Nav;
|
|
||||||
if (nav == null) return;
|
|
||||||
switch (_patrolStrategy)
|
switch (_patrolStrategy)
|
||||||
{
|
{
|
||||||
case PatrolStrategy.Wander:
|
case PatrolStrategy.Wander:
|
||||||
if (!nav.IsMoving) nav.WalkToRandom();
|
if (_enemy.Nav != null && !_enemy.Nav.IsMoving) _enemy.Nav.WalkToRandom();
|
||||||
break;
|
break;
|
||||||
// Pace / Waypoints:P6 实现
|
|
||||||
default:
|
case PatrolStrategy.Pace: // 撞墙/悬崖翻向的来回踱步(速度驱动,不依赖 nav)
|
||||||
if (!nav.IsMoving) nav.WalkToRandom();
|
var mv = _enemy.Movement;
|
||||||
|
if (mv != null && (mv.IsWallAhead || mv.IsLedgeAhead)) _paceDir = -_paceDir;
|
||||||
|
_enemy.MoveInDirection(_paceDir);
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user