feat: Update enemy AI and movement systems
- Enhanced Physics2D layer collision report with new interactions between Player and Enemy layers. - Refactored BD_InvestigateLastKnown to streamline animation handling and improve readability. - Simplified BD_MaintainCombatDistance by consolidating movement stop logic. - Updated BD_MoveToPlayer to set AI phase on start. - Improved BD_Patrol logic with better handling of stuck states and path failures. - Enhanced BD_PatrolWaypoints to manage stuck conditions and retry logic more effectively. - Refined BD_ReturnToHome to remove unnecessary animation calls. - Updated BD_WalkRandom to ensure AI phase is set correctly on start. - Improved EnemyAbilityBase to delegate target facing to the movement system. - Enhanced EnemyBase with new movement methods for better control. - Refactored EnemyMovement to introduce a new input system for handling movement and facing. - Added EnemyMoveInput struct to encapsulate movement intentions. - Updated Physics2DSettings to reflect new layer collision matrix. - Introduced RTK CLI instructions for optimized command usage.
This commit is contained in:
@@ -38,11 +38,22 @@ namespace BaseGames.Enemies.AI
|
||||
[Tooltip("每个路点到达后等待时长(s)")]
|
||||
[SerializeField] private float m_WaitAtWaypoint = 0f;
|
||||
|
||||
// 首次启动重试间隔:OnStart() 的第一次 RequestCurrent() 可能因 NavAgent 尚未完成
|
||||
// UpdateMappedPosition()(脚本执行顺序问题)而静默失败。此值只需大于一帧即可。
|
||||
private const float InitialRetryDelay = 0.05f;
|
||||
|
||||
// 正常巡逻中卡住的重试间隔:必须足够长,使任何在途 PB2d 路径请求
|
||||
// (Pending → Finished → HandlePathRequest 消费)都已处理完毕,避免竞争覆盖。
|
||||
private const float StuckRetryDelay = 0.5f;
|
||||
|
||||
private EnemyBase _enemy;
|
||||
private int _index = 0;
|
||||
private int _dir = 1;
|
||||
private float _waitTimer = 0f;
|
||||
private bool _waiting = false;
|
||||
private int _index = 0;
|
||||
private int _dir = 1;
|
||||
private float _waitTimer = 0f;
|
||||
private bool _waiting = false;
|
||||
private float _stuckTimer = 0f;
|
||||
private bool _pathFailed = false;
|
||||
private bool _hasMoved = false; // 首次成功开始移动后置 true
|
||||
|
||||
// ── 统一路点访问 ────────────────────────────────────────────────────
|
||||
private int WaypointCount =>
|
||||
@@ -68,9 +79,19 @@ namespace BaseGames.Enemies.AI
|
||||
public override void OnStart()
|
||||
{
|
||||
if (WaypointCount == 0) return;
|
||||
_waiting = false;
|
||||
_waitTimer = 0f;
|
||||
_waiting = false;
|
||||
_waitTimer = 0f;
|
||||
_stuckTimer = 0f;
|
||||
_pathFailed = false;
|
||||
_hasMoved = false;
|
||||
_enemy?.SetAiPhase(AiPhase.Patrol);
|
||||
|
||||
if (_enemy?.Nav != null)
|
||||
{
|
||||
_enemy.Nav.OnGoalReached += HandleGoalReached;
|
||||
_enemy.Nav.OnNavPathFailed += HandlePathFailed;
|
||||
}
|
||||
|
||||
RequestCurrent();
|
||||
}
|
||||
|
||||
@@ -86,38 +107,73 @@ namespace BaseGames.Enemies.AI
|
||||
_waiting = false;
|
||||
Advance();
|
||||
RequestCurrent();
|
||||
return TaskStatus.Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 wp = GetWaypoint(_index);
|
||||
float sqrDist = ((Vector2)_enemy.transform.position - wp).sqrMagnitude;
|
||||
|
||||
if (sqrDist <= m_ArriveRadius * m_ArriveRadius)
|
||||
// 兜底重试:用时间门控避免与 PB2d 的 Finished-状态路径请求产生竞争。
|
||||
// 首次启动前(_hasMoved=false)使用短延迟,处理 NavAgent 位置映射尚未就绪的情况;
|
||||
// 正常巡逻中使用长延迟,确保在途路径请求已被 HandlePathRequest 消费完毕。
|
||||
if (_enemy.Nav != null)
|
||||
{
|
||||
if (!_enemy.Nav.IsMoving)
|
||||
{
|
||||
if (m_WaitAtWaypoint > 0f)
|
||||
_stuckTimer += Time.deltaTime;
|
||||
float retryDelay = _hasMoved ? StuckRetryDelay : InitialRetryDelay;
|
||||
if (_stuckTimer >= retryDelay)
|
||||
{
|
||||
_waiting = true;
|
||||
_waitTimer = m_WaitAtWaypoint;
|
||||
_enemy.StopMovement();
|
||||
}
|
||||
else
|
||||
{
|
||||
Advance();
|
||||
_stuckTimer = 0f;
|
||||
_pathFailed = false;
|
||||
RequestCurrent();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_enemy.MoveTo(wp);
|
||||
_enemy.Movement?.FaceTarget(wp);
|
||||
_hasMoved = true;
|
||||
_stuckTimer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
return TaskStatus.Running;
|
||||
}
|
||||
|
||||
public override void OnEnd() => _enemy?.StopMovement();
|
||||
public override void OnEnd()
|
||||
{
|
||||
if (_enemy?.Nav != null)
|
||||
{
|
||||
_enemy.Nav.OnGoalReached -= HandleGoalReached;
|
||||
_enemy.Nav.OnNavPathFailed -= HandlePathFailed;
|
||||
}
|
||||
_enemy?.StopMovement();
|
||||
}
|
||||
|
||||
// ── 内部辅助 ────────────────────────────────────────────────────────
|
||||
private void HandleGoalReached()
|
||||
{
|
||||
_hasMoved = true;
|
||||
_stuckTimer = 0f;
|
||||
_pathFailed = false;
|
||||
if (m_WaitAtWaypoint > 0f)
|
||||
{
|
||||
_waiting = true;
|
||||
_waitTimer = m_WaitAtWaypoint;
|
||||
_enemy?.StopMovement();
|
||||
}
|
||||
else
|
||||
{
|
||||
Advance();
|
||||
RequestCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
// 路径失败时不在回调中立即重试——此时 NavAgent.HandlePathRequest 尚未调用
|
||||
// currentPathRequest.Reset(),直接提交新请求会被随后的 Reset() 覆盖清除。
|
||||
// 改为设置标志,交由 OnUpdate 的计时兜底在下一帧安全重试。
|
||||
private void HandlePathFailed()
|
||||
{
|
||||
_pathFailed = true;
|
||||
_stuckTimer = 0f; // 重置计时器,使兜底在 StuckRetryDelay 后触发
|
||||
}
|
||||
|
||||
private void RequestCurrent()
|
||||
{
|
||||
if (WaypointCount == 0) return;
|
||||
|
||||
Reference in New Issue
Block a user