① 架构 ② 行为树结构 ③ 战斗决策 ④ 攻击扩展 ⑤ 实测踩坑

① 架构概览

AIController + BehaviorTree + Blackboard + 蓝图派生 Pawn + AI 子蓝图。

AI 敌人的 Pawn 不是独立新建的,而是角色蓝图派生的子蓝图(保留完整角色 Mesh / 动画 / 蒙太奇 / 技能图表,只改控制器和输入属性)。整套 AI 由 6 个核心资产 + 4 个攻击扩展资产组成:

资产职责
CharacterEnemyBlueprint(子蓝图)AIControllerClass=EnemyAIController;AutoPossessPlayer=Disabled(关键,不能让 PIE 里玩家控制器抢占);Tags += "Enemy"
EnemyAIControllerRunBehaviorTree 入口;OnPossess 时写黑板(HomeLocation / bEngaged=false)
EnemyBehaviorTreeSelector 调度三个分支(回家/战斗追击/待机),服务 0.5s 检测
EnemyBlackboard黑板键:bEngaged、bWantsAttack、DistanceToTarget、HomeLocation、TargetActor
EnemyCombatActionTask(BTTask)执行攻击动作:普攻五连蒙太奇 / 闪电技能 / 瞬移飞行
EnemyTargetService(BTService)每 0.5s 刷新 DistanceToTarget、掷骰 bEngaged 黏性锁定

导航系统:关卡原本 NavMeshBoundsVolume 未启用(enable_navigation_system=False)。本任务顺带启用并新建 30000×30000×2000 的大体积(tile=11163),否则 AI MoveTo 不可用。

② 行为树结构

Selector 单根,三个分支左→右优先级递减。

Root
└ Selector【服务 EnemyTargetService,Interval=0.5,挂根层 ⇒ 待机时也检测】
   ├ 分支1 回家
   │   ├ 装饰器:DistanceToTarget > 35000(cm = 350m)
   │   │   FlowAbortMode=Both:真→抢占下面所有分支;假→放弃本分支
   │   ├ MoveTo:HomeLocation,AcceptableRadius=300
   │   └ Wait 2.0
   ├ 分支2 战斗/追击
   │   ├ 装饰器:bEngaged 为 true(Abort=LowerPriority)
   │   └ Selector
   │       ├ 攻击序列
   │       │   ├ 装饰器:bWantsAttack 为 true(抢占追击 MoveTo)
   │       │   └ EnemyCombatActionTask
   │       └ MoveTo:TargetActor,AcceptableRadius=600(追击)
   └ 分支3 待机:Wait 3.0

关键机制。bEngaged 是黏性的——进 100m 就锁定为 true,只有 >350m 才解除(避免敌人在边缘反复切换)。bWantsAttack 由 EnemyTargetService 掷骰(Random < 0.35 且冷却完毕)写入,解决"追击 MoveTo 常驻运行会饿死攻击分支"的经典问题。EnemyCombatActionTask 开头必须立刻清掉 bWantsAttack=false,否则冷却门形同虚设。

③ 战斗决策逻辑(距离段分档)

EnemyCombatActionTask 按距离自动选择动作;总闸冷却 4~8s 防止 AI 刷屏。

距离段候选动作实现冷却
< 1500cm(15m)普攻五连调角色蓝图事件 → 顺序播 13_combo_1~5 五段蒙太奇;每段 0.25s 出追踪弹(EnemyTrackBullet,归航 6000、伤害 20);ApplyDamage 只对 GetPlayerPawn(0)、距离≤60m(绝不追/伤敌人蓝图)3~6s
1500~5000闪电技能 → 普攻播 04_beam_all(无伤害,纯表演)→ 等 1s → 接普攻10~15s
5000~15000瞬移 → 飞行瞬移=播瞬移蒙太奇 + ProjectPointToNavigation(必须判成功布尔,失败→不位移)+ SetActorLocation;飞行=MOVE_Flying + Launch(0,0,500) 悬 3.5s 后 MOVE_Falling8~12s / 20~30s

④ 遁光追击 + 玩家命中(2026-09-29 ~ 10-01 新增)

四项扩展,PIE 实测全绿;①②③ 实装,④ 护盾格挡待人肉确认。

扩展实现
遁光追击(AI 版右键遁光)C++ 新增 ExecuteEnterTransformForAI / ExecuteExitTransformForAI(CharacterTransformBase 的 BlueprintCallable,完整复刻玩家右键遁光时序:溶解 0.2s→闪光→0.4s→进遁光态;退出反向)。BTTask EnemyDashChaseTask 调 Enter → 直线追击(4500cm/s,set 位置+Sweep)→ ≤12m → 调 Exit → 轮询等待退出完成(bIsInTransformedForm==false,1.5s 超时兜底)→ 就绪后写 bWantsAttack=true
五连完整普攻EnemyCombatActionTask 顺序播 1~5 蒙太奇(每段 0.25s 出 1 发追踪弹),5 段完 SetAttackCooldowns(now+4~7s)
玩家可命中 AIAI 必须"可被剑气/Q键六剑/普攻/闪电 命中"。泛化方式:新建接口 EnemyTargetInterface(FakerHP / CanTick / LightningPick / CE_LightningLink),EnemyBlueprint(原无人机)与 CharacterEnemyBlueprint 均实现;复制三个 Tag 版攻击资产(BezierBullet_TagEnemy/SwordBullet_TagEnemy/Lightning_Branch_TagEnemy,索敌改 Actor Has Tag("Enemy"));玩家 Attack 图 2 处 SpawnActor 指向副本。原资产零改动(无人机行为零回归)
护盾格挡子弹 ProjectileCollision Block on WorldDynamic → 撞护盾产生 Hit 被挡。护盾侧=E键护盾(Tick 轮询物理 E 键),自动化无法注入键鼠,待人肉按 E 验证

⑤ 实测踩坑(全部 PIE 端到端验证)

  1. 关卡导航系统原本禁用(enable_navigation_system=False + NullNavSysConfig)——旧的 100×100m NavMeshBoundsVolume 从未生效过。本任务顺带启用并新加了大体积。
  2. 角色蓝图继承的 AutoPossessPlayer=Player0 会让 PIE 里玩家控制器抢占这个 Pawn。子蓝图必须设 AutoPossessPlayer=Disabled,否则 AI 根本不由 AIC 控制。
  3. OnPossess 必须 RunBehaviorTree 之后再写黑板:先写黑板时黑板尚未装配,写入静默丢失(运行时读到 FLT_MAX)。
  4. 追击 MoveTo 常驻运行会饿死同层左侧的攻击分支(行为树不会重搜已激活分支)→ 引入 bWantsAttack 黑板键 + 装饰器 Abort=LowerPriority 抢占;且 BTTask 必须在执行开头清掉该键,否则冷却门变成唯一节流,攻击频率暴增且掷骰失效。
  5. TransformBase 的 CharacterMovement 默认 DefaultLandMovementMode=MOVE_Flying(继承类悬浮形态默认)——AI 直接持有时出生即 Flying、永不落地,加上飞行动作 Launch 后无重力刹不住 → 悬空 44m"隐形"。修法:AI 子蓝图 BeginPlay 强制 SetMovementMode(Walking)(PIE 105s 验证 C++ 不会打回)。
  6. 瞬移动作两层坑:① ProjectPointToNavigation 失败返回零向量,必须接成功布尔分支(失败→Finish(false));② 玩家 Pawn 出界被销毁时 GetPlayerPawn=None,读位置得零向量 → 投影到原点"成功"→ 传送到 (0,0,0)。位置源必须判有效性。
  7. BTTask 同步 FinishExecute 会饿死 ReceiveTickAI:攻击分支原先"执行完立刻 Finish"→ Tick 从不运行 → 0.4s 命中判定是死代码。任务型动作必须靠 ActionDuration 计时走到点再 Finish。
  8. 角色蓝图内置伤害管线只认 DroneTarget(EF_BP_BezierBullet 的 BeginOverlap 且 OtherActor==DroneTarget)——原角色是打无人机的,伤不到玩家 pawn。AI 的伤害必须自己 ApplyDamage(现方案:只对 GetPlayerPawn(0),距离≤6000,天然满足"只对角色产生伤害、不伤 EnemyBlueprint")。
  9. 限频真凶:出弹源从不写冷却变量(探针实测该值冻结 26 秒)→ 入口闸形同虚设 → 21 发/秒打崩 GPU。修=出弹后 SetAttackCooldowns(现 4~7s)。排查手段:加临时 Print 探针实测各链路计数,不要靠推断。
  10. 遁光中攻击 + 退出特效不出:①到达链 Exit 后同帧写攻击意愿,攻击抢在 0.1+0.4s 过渡前;②玩家距 12~18m 时到达落在进入过渡窗口(0.4s)内,Exit 被 C++ 守卫吞掉(日志 SKIPPED 实锤)→ 卡遁光。修=等待退出阶段(轮询+重试+超时兜底)+ CombatAction 入口双保险。

AI 敌人系统主资产 6 个 + 攻击扩展资产 4 个 + C++ 新增 2 个接口函数(h:419-432 / cpp:962-1026)。回滚=删所有新蓝图资产 + 删 C++ ForAI 接口。角色蓝图本体零改动。