前言

本文针对C++操作,并且针对在重写行为树组件中任务,装饰器,服务节点需要拾取黑板数据的操作

在虚幻引擎重写行为树中的任务,装饰器,服务节点时,通常需要操作与之关联的黑板中的数据。黑板中的数据获取方式从UBlackboardComponent中可以查到大致可分为两种方式:通过给定FName名称,通过KeyID(FBlackboard::FKey类型)

通过名称相对较好理解,但是通过KeyID,相对来说就麻烦一些,主要需要思考ID到底在哪里来。

在使用官方提供的行为树节点时,我们是能看到官方给定的节点是带有选项方式关联黑板数据,例如截图:

MoveTo任务节点细节面板截图
MoveTo任务节点细节面板截图

通过面板直接拾取关联黑板中的数据使得操作更加方便和安全。

源码

从查找源码不难发现官方实现方法。我们可以通过查阅UBTTask_MoveTo源码找到是实现。首先在UBTTask_MoveTo继承了UBTTask_BlackboardBase,在UBTTask_BlackboardBase的头文件中,他添加了成员变量BlackboardKey,这是用来获取黑板数据的关键。源码如下:

c++
1
2
3
/** blackboard key selector */
UPROPERTY(EditAnywhere, Category=Blackboard)
struct FBlackboardKeySelector BlackboardKey;

必要操作

添加完BlackboardKey后,需要重写虚函数InitializeFromAsset,这一部非常重要,否则获取黑板中的属性ID会出问题。

c++
1
2
3
//头文件中
/** initialize any asset related data */
virtual void InitializeFromAsset(UBehaviorTree& Asset) override;
c++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//源文件中实现
void UBTTask_BlackboardBase::InitializeFromAsset(UBehaviorTree& Asset)
{
	Super::InitializeFromAsset(Asset);

	UBlackboardData* BBAsset = GetBlackboardAsset();
	if (BBAsset)
	{
		BlackboardKey.ResolveSelectedKey(*BBAsset);
	}
	else
	{
		UE_LOG(LogBehaviorTree, Warning, TEXT("Can't initialize task: %s, make sure that behavior tree specifies blackboard asset!"), *GetName());
	}
}

添加类型约束

对于黑板中的数据进行关联拾取,FBlackboardKeySelector类型数据同时提供了类型约束,即只能拾取某些类型数据,注意需要填写在构造函数中。参照UBTTask_MoveTo源码如下:

c++
1
2
3
// accept only actors and vectors
BlackboardKey.AddObjectFilter(this, GET_MEMBER_NAME_CHECKED(UBTTask_MoveTo, BlackboardKey), AActor::StaticClass());
BlackboardKey.AddVectorFilter(this, GET_MEMBER_NAME_CHECKED(UBTTask_MoveTo, BlackboardKey));

对于类型约束,可以添加多种约束。对于对象型数据还可以指针数据的类型。

当存在多种类型拾取,如何区分?

当添加多种约束后如何区分到底拾取的是那种类型?这部分可以通过阅读源码了解,例如在UBTTask_MoveTo中可以找到以下源码:

c++
1
2
3
4
5
6
7
8
9
if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Object::StaticClass())
{
    UObject* KeyValue = MyBlackboard->GetValue<UBlackboardKeyType_Object>(BlackboardKey.GetSelectedKeyID());
    AActor* TargetActor = Cast<AActor>(KeyValue);
}
else if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Vector::StaticClass())
{
    const FVector TargetLocation = MyBlackboard->GetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID());
}

结语

以上就是解决在重写行为树中的任务,装饰器,服务节点时,需要获取黑板数据的方法,通过阅读UBTTask_MoveTo类源码可以获得所有内容。