diff --git a/Assets/_Game/Scripts/Enemies/EnemyBase.cs b/Assets/_Game/Scripts/Enemies/EnemyBase.cs index 9fba0258..f563e4ef 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyBase.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyBase.cs @@ -5,9 +5,6 @@ using BaseGames.Core.Events; using BaseGames.Core.Pool; using BaseGames.Enemies.States; using BaseGames.Enemies.Abilities; -#if GRAPH_DESIGNER -using Opsive.BehaviorDesigner.Runtime; -#endif namespace BaseGames.Enemies { @@ -57,20 +54,6 @@ namespace BaseGames.Enemies /// [SerializeField] private BaseGames.Core.Events.TransformEventChannelSO _onPlayerSpawned; -#if GRAPH_DESIGNER - [Header("BT Tick 分级(LOD)")] - [Tooltip("Idle 阶段 BT Tick 最小间隔(s);0 = 每帧全速。")] - [SerializeField] private float _btIdleTickInterval = 0.30f; - [Tooltip("Patrol/ReturnHome 阶段 BT Tick 间隔(s)")] - [SerializeField] private float _btPatrolTickInterval = 0.15f; - [Tooltip("Alert/Investigate 阶段 BT Tick 间隔(s)")] - [SerializeField] private float _btAlertTickInterval = 0.08f; - [Tooltip("Chase 阶段 BT Tick 间隔(s)")] - [SerializeField] private float _btChaseTickInterval = 0.05f; - [Tooltip("Combat 阶段 BT Tick 间隔(s);0 = 每帧全速")] - [SerializeField] private float _btCombatTickInterval = 0f; -#endif - // ── 导航代理(IPathAgent;由 EnemyNavAgent 实现)─────────────────── // 通过接口引用,避免对 Navigation 程序集的直接依赖。 // 由子类 / Inspector 注入,或者运行时 GetComponent() 获取。 @@ -132,9 +115,6 @@ namespace BaseGames.Enemies [SerializeField] private AiPhase _dbg_AiPhase; [SerializeField] private bool _dbg_HasPlayer; [SerializeField] private Vector2 _dbg_LastKnownPos; -#if GRAPH_DESIGNER - [SerializeField] private float _dbg_BtTickInterval; -#endif #endif // POCO 状态对象字典:枚举保持对外 API 不变。 @@ -254,9 +234,9 @@ namespace BaseGames.Enemies /// 状态效果管理器(冻结、灼烧、睡眠等)。 public StatusEffects.EnemyStatusEffectManager StatusEffects => _statusEffects; private StatusEffects.EnemyStatusEffectManager _statusEffects; -#if GRAPH_DESIGNER - public BehaviorTree BehaviorTree => _behaviorTree; -#endif + /// 决策层组件(BrainGraph)。供 EnemyQuotaManager 做活跃数量 LOD 裁剪等使用。 + public EnemyAiBrain Brain => _brain; + private EnemyAiBrain _brain; // ── BD 行为树接口(虚方法)──────────────────────────────────────── @@ -369,14 +349,12 @@ namespace BaseGames.Enemies => _movement?.JumpToTarget(target); /// - /// 调整 BehaviorTree Tick 频率(非警觉=降频,警觉=高频)。 - /// 由 BD_SetAlert 调用(架构 07_EnemyModule §13.5)。 + /// 调整决策 Tick 频率(非警觉=降频,警觉=高频)。 + /// 由外部(警戒/状态效果)调用(架构 07_EnemyModule §13.5)。 /// public virtual void SetAggroTickRate(bool isAggro) { -#if GRAPH_DESIGNER - _btCurrentInterval = isAggro ? _btAlertTickInterval : _btIdleTickInterval; -#endif + // LOD tick 速率控制迁移到后续 AiScheduler 阶段 } // ── 警戒传播(Group Alert)──────────────────────────────────────── @@ -468,20 +446,6 @@ namespace BaseGames.Enemies _currentAiPhase = phase; OnAiPhaseChanged?.Invoke(phase); -#if GRAPH_DESIGNER - // 按行为阶段动态调整 BT Tick 频率(5 档 LOD) - _btCurrentInterval = phase switch - { - AiPhase.Patrol => _btPatrolTickInterval, - AiPhase.Alert => _btAlertTickInterval, - AiPhase.Investigate => _btAlertTickInterval, - AiPhase.Chase => _btChaseTickInterval, - AiPhase.Combat => _btCombatTickInterval, - AiPhase.ReturnHome => _btPatrolTickInterval, - _ => _btIdleTickInterval, // Idle + 未来新阶段兜底 - }; -#endif - if (_autoPlayPhaseAnimation && _animancer != null && _animConfig != null) { var clip = phase switch @@ -588,6 +552,7 @@ namespace BaseGames.Enemies _statusEffects = GetComponent(); _threatAssessor = GetComponent(); _pooledObject = GetComponent(); + _brain = GetComponent(); _abilities.CollectFrom(gameObject); _colliders = GetComponentsInChildren(true); @@ -602,20 +567,6 @@ namespace BaseGames.Enemies // 订阅玩家生成事件(PlayerController.Start 广播),避免每个敌人独立 FindWithTag // 订阅在 OnEnable 中处理 - -#if GRAPH_DESIGNER - _behaviorTree = GetComponent(); - if (_behaviorTree != null) - { - _behaviorTree.StartWhenEnabled = false; - _behaviorTree.PauseWhenDisabled = true; - // Manual 模式:由 EnemyBase.Update 按 AiPhase 分级节流 Tick。 - _behaviorTree.UpdateMode = Opsive.BehaviorDesigner.Runtime.Components.UpdateMode.Manual; - _btManualMode = true; - _btCurrentInterval = _btIdleTickInterval; - _behaviorTree.StartBehavior(); - } -#endif } protected virtual void Update() @@ -626,34 +577,11 @@ namespace BaseGames.Enemies if (_playerTransform != null && _stats != null) _stats.SqrDistanceToPlayer = ((Vector2)_playerTransform.position - (Vector2)transform.position).sqrMagnitude; -#if GRAPH_DESIGNER - // BT Tick LOD:按当前 AiPhase 分级节流,降低空闲状态的 BT 开销。 - if (_btManualMode && _behaviorTree != null) - { - float interval = _btCurrentInterval; - if (interval <= 0f) - { - _behaviorTree.Tick(); - } - else - { - _btTickTimer += Time.deltaTime; - if (_btTickTimer >= interval) - { - _btTickTimer -= interval; - _behaviorTree.Tick(); - } - } - } -#endif #if UNITY_EDITOR _dbg_CurrentState = _currentState; _dbg_AiPhase = _currentAiPhase; _dbg_HasPlayer = _playerTransform != null; _dbg_LastKnownPos = LastKnownPlayerPosition; -#if GRAPH_DESIGNER - _dbg_BtTickInterval = _btCurrentInterval; -#endif #endif } @@ -691,26 +619,14 @@ namespace BaseGames.Enemies protected virtual void OnDestroy() { } - - - // BehaviorTree 引用(#if GRAPH_DESIGNER 保护,避免空引用) -#if GRAPH_DESIGNER - private BehaviorTree _behaviorTree; - private bool _btManualMode; - private float _btTickTimer; - private float _btCurrentInterval; -#endif - /// - /// 停止行为树(死亡演出 / 出场演出等期间调用,防止 BT 继续 Tick 覆盖演出逻辑)。 - /// 内部使用 #if GRAPH_DESIGNER 保护,调用方无需处理条件编译。 + /// 通知决策层终止(死亡演出 / 出场演出等期间调用,防止决策继续覆盖演出逻辑)。 + /// 语义为"通知决策层终止",与 PerformDeath 的 Died 信号幂等(重复 Died 无害)。 /// 供配置型行为组件(如 EnemyDeathSequence)调用,故为 public。 /// public void StopBehaviorTree() { -#if GRAPH_DESIGNER - _behaviorTree?.StopBehavior(); -#endif + _brain?.Send(BaseGames.AI.AiSignal.Died); } /// @@ -744,6 +660,9 @@ namespace BaseGames.Enemies _deathSequenceActive = false; ForceState(EnemyStateType.Dead); + // 通知决策层敌人已死亡 + _brain?.Send(BaseGames.AI.AiSignal.Died); + // 死亡时清除所有状态效果 _statusEffects?.Clear(); @@ -804,25 +723,21 @@ namespace BaseGames.Enemies // 重置能力冷却 _abilities.InterruptAll(InterruptReason.Dead); -#if GRAPH_DESIGNER - _behaviorTree?.StartBehavior(); -#endif + // 重置决策层(回到 Entry、清临时态) + _brain?.ResetBrain(); // 通知配置型出生行为组件(如 EnemyAbilityTrigger)执行出生触发逻辑 Spawned?.Invoke(); } /// - /// 对象归还到池时调用,清理临时状态,停止 BT。 + /// 对象归还到池时调用,清理临时状态。 /// public virtual void OnDespawn() { _abilities.InterruptAll(InterruptReason.Dead); _nav?.StopNavigation(); - -#if GRAPH_DESIGNER - if (_behaviorTree != null) _behaviorTree.enabled = false; -#endif + // GO 停用时 EnemyAiBrain.Update 自然停止,无需显式处理。 } #if UNITY_EDITOR diff --git a/Assets/_Game/Scripts/Enemies/EnemyQuotaManager.cs b/Assets/_Game/Scripts/Enemies/EnemyQuotaManager.cs index 8bc9e25c..f10fdcab 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyQuotaManager.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyQuotaManager.cs @@ -101,23 +101,22 @@ namespace BaseGames.Enemies if (e != null) _indexMap[e] = i; } -#if GRAPH_DESIGNER for (int i = n - 1; i >= 0; i--) { var enemy = _registered[i]; if (enemy == null) { _registered.RemoveAt(i); continue; } - var bt = enemy.BehaviorTree; + var brain = enemy.Brain; bool active = i < _maxActiveBehaviorTrees; - if (bt != null && bt.enabled != active) + if (brain != null && brain.enabled != active) { - bt.enabled = active; + // 禁用 brain 即停其 Update/Tick,等价于旧的禁用行为树。 + brain.enabled = active; // 同步暂停/恢复感知系统,避免远处敌人无效 tick enemy.SensorHub?.SetSuspended(!active); } } -#endif } } }