diff --git a/Assets/_Game/Scripts/Enemies/EnemyBase.cs b/Assets/_Game/Scripts/Enemies/EnemyBase.cs index 1043e5a7..f0f84fcb 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyBase.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyBase.cs @@ -377,9 +377,6 @@ namespace BaseGames.Enemies // LOD tick 速率控制迁移到后续 AiScheduler 阶段 } - // ── 警戒传播(Group Alert)──────────────────────────────────────── - private static readonly UnityEngine.Collider2D[] _alertBuffer = new UnityEngine.Collider2D[32]; - // ── 弹反(Parry)响应 ────────────────────────────────────────────── private bool _wasParried; private float _parryTimestamp; @@ -417,39 +414,6 @@ namespace BaseGames.Enemies ScheduleStateRecovery(EnemyStateType.Stagger, staggerDuration); } - /// - /// 通知半径内的其他敌人进入 Alert 阶段(Group Alert 广播)。 - /// 配合 BD_BroadcastAlert 在进入 Chase 阶段时调用。 - /// - public void AlertNearby(float radius) - { - if (radius <= 0f) return; - int count = Physics2D.OverlapCircleNonAlloc(transform.position, radius, _alertBuffer); - for (int i = 0; i < count; i++) - { - if (_alertBuffer[i] == null) continue; - var enemy = _alertBuffer[i].GetComponentInParent(); - if (enemy == null || enemy == this) continue; - enemy.ReceiveAlert(_playerTransform, LastKnownPlayerPosition); - } - } - - /// - /// 接收来自邻近敌人的警戒广播。 - /// 当前处于 Idle / Patrol 时切换到 Alert;Chase / Combat 中不降级。 - /// - public void ReceiveAlert(Transform sharedPlayerTransform, Vector2 lastKnownPos) - { - if (!IsAlive) return; - if (IsEngaged) return; - - // 同步玩家引用(若本敌人尚未感知到玩家) - if (sharedPlayerTransform != null && _playerTransform == null) - _playerTransform = sharedPlayerTransform; - LastKnownPlayerPosition = lastKnownPos; - PlayLocomotionClip(LocomotionMode.Face); - } - /// 按当前移动模式播放步态动画(由 EnemyLocomotion 在模式变化时调用)。 public void PlayLocomotionClip(LocomotionMode mode) { @@ -550,6 +514,8 @@ namespace BaseGames.Enemies _nav = GetComponent() ?? new NullPathAgent(); _locomotion = GetComponentInChildren(true); + if (_locomotion == null) + Debug.LogError($"EnemyBase 未找到 EnemyLocomotion 组件:{name}", this); if (_movement == null) _movement = GetComponent(); _poiseSource = GetComponent(); _sensorHub = GetComponentInChildren(); diff --git a/Assets/_Game/Scripts/Enemies/EnemyMovement.cs b/Assets/_Game/Scripts/Enemies/EnemyMovement.cs index 5eddd415..af4cca99 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyMovement.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyMovement.cs @@ -502,7 +502,7 @@ namespace BaseGames.Enemies _turnCoroutine = null; // 转身完成后恢复运动动画:Turn 覆盖了之前的 Walk/Run, - // 上层(EnemyBase.SetAiPhase)只在阶段切换时播放一次动画,不会在此处重播。 + // 上层(EnemyLocomotion 按模式切换)只在切换时播放一次步态动画,不会在此处重播。 ResumeMovementAnimation(); } diff --git a/Assets/_Game/Scripts/Enemies/EnemyStatsSO.cs b/Assets/_Game/Scripts/Enemies/EnemyStatsSO.cs index 1ac7eed9..48ff63d3 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyStatsSO.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyStatsSO.cs @@ -52,10 +52,5 @@ namespace BaseGames.Enemies [Header("受击分级")] [Tooltip("Stagger / KnockUp 伤害阈值及击飞参数")] public HitTierConfig HitTiers; - - [Header("警戒传播(Group Alert)")] - [Tooltip("发现玩家时通知周围同伴进入 Alert 的半径(m);0 = 关闭")] - [Min(0f)] - public float AlertBroadcastRadius = 0f; } } diff --git a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs index 80f3fe73..2a1dca90 100644 --- a/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs +++ b/Assets/_Game/Scripts/Enemies/Navigation/EnemyLocomotion.cs @@ -17,6 +17,7 @@ namespace BaseGames.Enemies [Header("Waypoints 策略参数")] [SerializeField] private Transform[] _waypoints; [SerializeField] private bool _pingPong; + [SerializeField] private float _waypointArriveRadius = 0.4f; private EnemyBase _enemy; private LocomotionMode _mode = LocomotionMode.Idle; @@ -116,7 +117,7 @@ namespace BaseGames.Enemies _enemy.MoveInDirection(_paceDir); break; - case PatrolStrategy.Waypoints: // 按序(loop 或 ping-pong)巡逻路点 + case PatrolStrategy.Waypoints: if (_waypoints == null || _waypoints.Length == 0) { if (!_warnedNoWaypoints) @@ -126,7 +127,10 @@ namespace BaseGames.Enemies } break; } - if (_enemy.Nav != null && !_enemy.Nav.IsMoving) + // 仅首次或"已到达当前路点"时推进并寻路——不依赖 IsMoving + // (PathBerserker2d 寻路跨帧异步,IsMoving 在寻路计算期间为 false,会误触发每帧推进)。 + if (_wpIndex < 0 || + Vector2.Distance(_enemy.transform.position, _waypoints[_wpIndex].position) <= _waypointArriveRadius) { AdvanceWaypoint(); _enemy.MoveTo(_waypoints[_wpIndex].position);