总览
Smart Object 的生产难点不是“做一个能用的椅子”,而是“项目里有 5000 个可用对象、十几种 AI、多人网络、World Partition 流送、内容团队每天改资产时,系统还能解释、调试和回退”。这一篇给项目规范。
命名规范
SOD_Chair_Sit
SOD_Door_Open
SOD_Workbench_Craft
BP_SO_Chair_Wood
BP_SO_Workbench_Blacksmith
Activity.Sit
Activity.Work.Craft
User.NPC.Civilian
SO.State.LockedByQuest
Event.SO.Work.Start
命名要让调试输出能读。看到 SOD_Workbench_Craft 和 Activity.Work.Craft,策划、程序和 TA 都知道它是工作台加工;看到 SO_01 和 Tag.A,谁也不知道怎么修。
调试流程
- 打开 Gameplay Debugger 的 Smart Object 类别,看对象数量、Active 数、Registered Components、Collection Entries。
- 看 Slot 颜色和状态:Free、Claimed、Occupied、Disabled。
- 看 Slot 方向和 Tags,确认 ActivityTags 写在正确位置。
- 如果查询失败,打开请求 DebugRejections,看 Definition/Object/Slot 哪一层拒绝。
- 对 BT/StateTree/Mass,额外看 ClaimHandle 是否存在、MoveTo 目标是否是 Slot Transform。
性能预算
查询半径、查询频率、候选排序和条件复杂度是主要成本。普通 AI 可以事件触发或低频查询;Mass 必须批处理和分层频率;World Conditions 里不要做昂贵逻辑。把“查找间隔”和“最大候选数”做成配置,不要散在各个任务里。
World Partition
USmartObjectComponent 有 bCanBePartOfCollection,说明对象可以聚合进 SmartObjectPersistentCollection。这样对象 Actor 流送出去时,系统仍可以查询和推理其 Smart Object 数据。生产项目里要明确哪些对象允许进 Collection:静态椅子、工作台、摊位可以;动态生成、强依赖 Actor 运行逻辑的对象要谨慎。
多人同步
Smart Object 占用应该由服务器权威。客户端可以预测 UI 和动画反馈,但 Claim/Occupied/Free 的状态不能各算各的。多人项目还要决定玩家和 AI 的 ClaimPriority:玩家交互是否能抢占 NPC,剧情 NPC 是否高于普通路人,死亡或断线时谁负责释放。
使用案例
开放世界城镇:静态座椅、摊位、工作台进入 Persistent Collection;路人 Mass 使用低频查询;剧情 NPC 使用普通 Actor AI 和更高优先级;玩家交互走服务器 Claim;任务系统通过 Enabled reason 禁用某些对象;调试时用 Gameplay Debugger 看对象和 Slot 状态。
架构分析
生产级系统最好把 Smart Object 包成三层:资产规范层定义 Definition/Slot/Tag;运行时服务层封装 Find/Claim/Use/Release;业务编排层由 BT、StateTree、GAS 或 Mass 调用。这样引擎 API 变化时,只改运行时服务层,内容资产和业务流程不被到处牵连。
项目落地
推荐两周试点节奏:第一周只做 SOD_Chair_Sit、SOD_Workbench_Craft 和统一 Find/Claim/Release 服务,接 Gameplay Debugger,把 Release 守卫写进 BT Task 或 StateTree Task;第二周接一个 Mass 路人案例、一个玩家交互案例和一个 World Partition 场景。试点验收标准不是对象数量,而是能解释每一次查找失败、每一次占用、每一次释放。
上线检查清单
- 每个 Definition 都能 Validate。
- 每个 Slot 都有清楚 Name、ActivityTags、方向和调试颜色。
- 每个 Find 后跨帧使用都必须 Claim。
- 每个 Claim 都有 Abort/Cancel/Destroy/ExternalStop 释放路径。
- 每个多人交互都由服务器决定 Claim。
- Mass 查询有 SearchInterval 和 Cooldown。
- World Partition 对象明确是否进 Persistent Collection。
- Gameplay Debugger 能解释对象数量、Slot 状态和 Tag。
- 所有 Tag 有文档,不允许临时乱建。
常见坑
- 内容团队只复制 Actor 不复制规范:Definition、Slot 和 Tag 很快失控。
- Release 靠业务自觉:必须封装到统一任务/组件里。
- 条件逻辑不可解释:AI 找不到对象时没人知道被哪层拒绝。
- World Partition 流送后对象消失:要区分运行时 Actor 和 Collection 数据。
- 多人客户端自行 Claim:线上会出现两个玩家或 AI 同时使用一个 Slot。
源码依据
USmartObjectComponent 的 bCanBePartOfCollection 说明 Smart Object 可以被 Persistent Collection 聚合。ASmartObjectPersistentCollection 和 WorldPartitionSmartObjectCollectionBuilder 负责大世界/流送相关数据。GameplayDebuggerCategory_SmartObject.cpp 会统计 Runtime Objects、Active Objects、Registered Components、Collection Entries,并绘制对象、Slot、Tag、状态颜色、方向和用户连线。USmartObjectSubsystem 是生产封装的核心依赖点。
源码路径索引
SmartObjectsModule/Public/SmartObjectPersistentCollection.hSmartObjectsModule/Public/SmartObjectSettings.hSmartObjectsModule/Private/GameplayDebuggerCategory_SmartObject.cppSmartObjectsEditorModule/Private/WorldPartitionSmartObjectCollectionBuilder.cppSmartObjectsModule/Public/SmartObjectComponent.h