CD Code Digest Hub /GTA V

AI 与 NPC 行为

10 分钟阅读 8 个章节 1 张图

返回总览。AI 横跨玩法脚本、GTA 的 Ped/事件/任务体系和 RAGE AI 基础设施。没有证据支持把整个体系简化为一个统一行为树或一个通用 NPC 脚本。

1. 分层决策#

脚本决定角色在当前剧情中扮演什么,原生 AI 决定怎样行走、进入车辆、战斗或逃跑。CTaskManager 继承 RAGE 的 aiTaskManager,并存在 Ped、Vehicle 专用管理和 TaskTree/TaskFSMClone 类型。[S3] 这说明任务有层级和可同步表示,不能仅用脚本阶段枚举解释 NPC 内部实现。

2. 一条 TASK 命令实际做了什么#

以 TASK_COMBAT_PED 等行为接口为例,commands_task.cpp 构造原生任务并调用 CScriptPeds::GivePedScriptedTask。[S1]

后者的关键路径非常值得注意:[S2,L1238]

  1. 在线模式先检查任务类型是否受网络支持。
  2. 根据脚本句柄寻找可修改的 CPed;无效时释放刚创建的任务。
  3. 若 Ped 是远端 clone 或正等待所有权变化,交给 NetworkInterface::GivePedScriptedTask 处理,而不是直接执行本地指令。
  4. 已有 Script Brain 的 Ped 不能任由其他脑脚本随意抢写行为;代码检查当前 brain 与目标 Ped 的关系。
  5. 对网络 NPC 的任务序列检查可同步任务数上限。
  6. 本地路径构建 CEventScriptCommand,移除旧同类事件,要求下一帧不对这次 intelligence 更新分片,再将事件加入 PedIntelligence 并登记脚本任务记录。

因此下达任务不等于 NPC 已经完成动作,也不一定意味着脚本立刻替换了全部任务树。读取 GET_SCRIPT_TASK_STATUS、实体条件和超时,才形成完整的脚本反馈闭环。

3. 事件优先级让角色能够被打断#

CEventHandler::HandleEvents 从 intelligence 取最高优先级事件,比较它与当前/历史事件的优先级,判断同类事件能否打断,处理可编辑响应,无有效响应时再寻找其他事件。[S4]

这使“按脚本走向一辆车”与“突然受伤、死亡或遭到威胁”能够在一个行为系统中仲裁。任务作者可以控制阻断环境反应、角色关系、战斗属性,但不应据此假设 NPC 永远执行最初命令。

每帧重新发送同一个移动或战斗任务,会不断刷新事件/任务入口,可能破坏动作连续性。更合适的内容写法是进入状态时下达一次,运行期间监测,只有目标或条件改变时重发。具体 Native 可能有自己的更新语义,应按接口判断。

4. Sequence 的表达能力与边界#

GivePedScriptedTask 对 NULL Ped 参数有特殊分支:把任务加入当前打开的序列;实际 Ped 再执行完整 sequence。这解释了许多脚本中“对 NULL 调用多个 TASK,然后 TASK_PERFORM_SEQUENCE”的写法,它不是漏传 NPC。[S2]

序列适合“转身—走到点—播放动画—进入车辆”等短流程;长任务和可被玩家打断的剧情仍需外层状态机。在线还会校验序列任务数及其中任务的迁移支持,部分 movement wrapper 实际同步的是子任务。不能把任意单机 sequence 原样搬到在线就假定可迁移。

5. Script Brain 和 Scenario 如何填充世界#

CScriptsForBrains 支持按实体模型、世界点、scenario ped 注册脚本脑,带激活范围、比例或集合信息,并负责安全运行判断和脚本流式启动。[S5] 它是“世界内容满足条件后挂上一段行为脚本”的机制,不是所有 NPC 的底层推理引擎。

Generic_Brain.sch 提供可覆写钩子:自定义初始化、请求资源、资源就绪、允许运行、创建、持续更新、销毁、逃跑,以及招呼/独白/互动动画等。[S6] 内容作者可以复用总体生命周期,只补人物语料、动画和局部反应。

Scenario 则提供世界中的生活动作和位置语义。任务可让 Ped 进入 WORLD_HUMAN_* 场景;需要搭建专属剧情时,先阻塞附近 scenario,避免原本的环境 NPC 与场景演员争用同一地点。Scenario、Script Brain、任务演员三者能够协作,也需要明确谁拥有当前角色行为。

6. 在线 NPC:逻辑阶段与执行控制分离#

FMMC 的 FM_Mission_Controller_Peds_Brain.sch 包含视线、动画能否打断、警戒/惊吓、敌对触发、任务失败等逻辑;FM_Mission_Controller_Peds.sch 则维护物品、显示、创建后处理和每帧更新,并频繁检查实体控制权。[S7][S8]

这体现两种权威:脚本主机决定任务阶段及警戒事实,实体拥有者执行受控制权约束的行为。两者可能在同一机器,也可能不同。主机迁移不等于所有 NPC 一起迁移;本地 UI 可以显示远端 NPC,但不能据此假定有权修改它。

在线 NPC 状态应能从广播的任务状态和实体状态恢复。纯本地 bool 如果决定全局警戒,却从未进入同步状态,那么后续接手的主机不会自然知道它;这是设计审查应追踪的数据路径,并非本次确认的具体漏洞。

7. 内容填充的实用组合#

目标体验可组合机制需要预留的异常出口
有生活感的路人Scenario + Generic Brain 对话/动作钩子被撞、惊吓、玩家远离
精确剧情演员局部 FSM + sequence + 同步场景动画未加载、受伤、任务退出
有节奏的敌人波次位置/掩体数据 + 战斗属性 + 原生 combat刷新不可见性、路径不可达、波次清理
多人巡逻/潜入可广播警戒状态 + 控制权判断 + 视线检查主机离开、实体迁移、迟加入

以少量稳定的行为组件组合出地点、角色、关系和台词变体,比为每一个人物复制完整 AI 更利于维护。高优先级角色可以提高更新及时性,但不能把所有 NPC 都设置成不分帧;本次未测量 AI CPU 成本或网络带宽。

源码证据#

编号位置
[S1]commands_task.cpp L987–1014 战斗任务及大量 GivePedScriptedTask 调用
[S2]script_cars_and_peds.cpp L1238–1361,网络转交、brain 限制、事件、sequence
[S3]TaskManager.h L23;同目录 TaskTree、TaskFSMClone
[S4]EventHandler.cpp L193 优先级;L275 事件处理
[S5]script_brains.cpp L168、L223、L254 注册;L387 安全检查;L423 流式请求
[S6]Generic_Brain.sch L18–121 钩子体系
[S7]FM_Mission_Controller_Peds_Brain.sch L70 视线;L93 动画打断;L1047/1157 敌对状态
[S8]FM_Mission_Controller_Peds.sch L181 物品清理;L1822 每帧更新

[S1]: <../../../GTAV Source/src/dev_ng/game/script/commands_task.cpp> [S2]: <../../../GTAV Source/src/dev_ng/game/script/script_cars_and_peds.cpp> [S3]: <../../../GTAV Source/src/dev_ng/game/task/System/TaskManager.h> [S4]: <../../../GTAV Source/src/dev_ng/game/event/EventHandler.cpp> [S5]: <../../../GTAV Source/src/dev_ng/game/script/script_brains.cpp> [S6]: <../../../GTAV Source/script/dev_ng/singleplayer/scripts/Ambient/Peds/GenericBrain/Generic_Brain.sch> [S7]: <../../../GTAV Source/script/dev_ng/multiplayer/scripts/modes/freemode/FM_Mission_Creator/FM_Mission_Controller/FM_Mission_Controller_Peds_Brain.sch> [S8]: <../../../GTAV Source/script/dev_ng/multiplayer/scripts/modes/freemode/FM_Mission_Creator/FM_Mission_Controller/FM_Mission_Controller_Peds.sch>