总览
Smart Object 管“可用点”和“占用状态”,但它本身不规定你的角色怎么坐下、怎么开门、怎么加工。行为通过 USmartObjectBehaviorDefinition 扩展。你可以把它理解成 Slot 给使用者的一张说明书:这个 Slot 被使用时,该交给哪个行为系统执行,带哪些配置。
行为来源
| 行为方案 | 适合场景 | 典型类型 |
|---|---|---|
| GameplayBehavior | 普通 AI 行为、动画、蓝图配置 | UGameplayBehaviorSmartObjectBehaviorDefinition |
| GameplayInteractions | 复杂交互流程、事件、StateTree | UGameplayInteractionSmartObjectBehaviorDefinition |
| Mass SmartObject | 大量实体、计时行为、ZoneGraph | USmartObjectMassBehaviorDefinition |
| 项目自定义 Definition | GAS、任务系统、自定义动画系统 | 继承 USmartObjectBehaviorDefinition |
使用案例
坐椅子行为可以拆成四段:移动到入口,面向椅子,播放坐下 Montage,进入 Idle。Smart Object 负责前两段的数据:Slot Transform 和入口注解;GameplayBehavior 或项目逻辑负责后两段:动画、对齐、状态改变和结束回调。
开门行为通常不需要长时间 Occupied。玩家或 AI Claim 门的 Slot,移动到门前,开始 Occupied,触发门蓝图打开,收到动画完成事件后释放。多人项目里还要决定门是只在服务器改变状态,还是客户端预测播放反馈。
架构分析
USmartObjectBehaviorDefinition 是抽象基类,源码里几乎不放逻辑,目的是允许不同框架挂自己的配置。UGameplayBehaviorSmartObjectBehaviorDefinition 只有一个核心属性:UGameplayBehaviorConfig* GameplayBehaviorConfig。Behavior Tree 或 AI Task 拿到 ClaimHandle 后,通过 Subsystem 查询对应 Definition,再把配置交给 GameplayBehavior 执行。
这意味着 BehaviorDefinition 不应该保存“当前谁在用我”这种运行时状态;运行时状态在 Subsystem 的 RuntimeSlot 里。Definition 负责“怎么用”,Runtime 负责“现在谁在用”。
自定义行为定义
UCLASS(EditInlineNew)
class UMyAbilitySmartObjectDefinition : public USmartObjectBehaviorDefinition
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, Category="Ability")
TSubclassOf<UGameplayAbility> AbilityClass;
UPROPERTY(EditDefaultsOnly, Category="Ability")
FGameplayTag InteractionTag;
};
使用时,Claim 成功后调用 GetBehaviorDefinition<UMyAbilitySmartObjectDefinition>(ClaimHandle),拿到 AbilityClass,再由 ASC 激活能力。这样 Smart Object 不需要知道 GAS 细节,GAS 也不需要知道 Definition 的资产结构。
项目落地
小团队可以先用 GameplayBehaviorSmartObjects 快速起步;复杂项目建议把行为执行封成自己的接口,例如 ISmartObjectInteractionRunner。BT、StateTree、GAS、玩家交互都通过同一个 Runner 去 Occupy、执行、Release,这样 Release 规则和日志统一。
常见坑
- 把行为状态写进 Definition:Definition 是共享资产,不能保存每个实例的运行时状态。
- Slot 行为类型不唯一:同一类 BehaviorDefinition 只保留一个,避免取第一个时不可预测。
- 动画对齐只靠 Slot Transform:很多坐下、开门需要 Entrance Annotation 或 Motion Warping。
- 行为失败不释放:动画被打断、Ability Cancel、AI 死亡都要释放。
- GameplayBehavior 能做一切:复杂交互流程更适合 GameplayInteractions StateTree 或项目自定义框架。
源码依据
USmartObjectBehaviorDefinition 定义在 SmartObjectDefinition.h,是 Smart Object 与行为框架之间的抽象扩展点。UGameplayBehaviorSmartObjectBehaviorDefinition 继承它,并保存 UGameplayBehaviorConfig。USmartObjectSubsystem::MarkSlotAsOccupied 和 GetBehaviorDefinition 会根据 ClaimHandle 和 DefinitionClass 找到对应行为定义。
源码路径索引
SmartObjectsModule/Public/SmartObjectDefinition.hGameplayBehaviorSmartObjectsModule/Public/GameplayBehaviorSmartObjectBehaviorDefinition.hGameplayBehaviorSmartObjectsModule/Public/AI/AITask_UseGameplayBehaviorSmartObject.hGameplayBehaviorSmartObjectsModule/Private/AI/AITask_UseGameplayBehaviorSmartObject.cpp