在上一篇文章中,我们介绍了行为树与黑板资源,及寻路组件,了解了怎么使用这些组件,在本文中,我们将创建一个AICharacter,并运用上行为树以及黑板资源。现在我们创建一个新的character,并命名为AIBlogCharacter。该character要做的事情也很简单,就是发现hero,然后走到该hero处。创建好AIBlogCharacter后,我们新建一个AIBlogController,这个类是用来控制我们的AI的,如下图所示:
接着在我们的AICharacter的构造函数中,为我们的aicontrol赋值,如下所示:
AAIBlogCharacter::AAIBlogCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
AIControllerClass = AAIBlogController::StaticClass();
}
为了使我们的AI能看见人物,我们需要为我们的AI类添加一个成员UPawnSensingComponent,并且在构造函数中创建出来,使用UPROPERTY的原因,是我们之后将基于该AI类创建一个蓝图类,这样便可在编辑器中调整UPawnSensingComponent,如下所示:
UPROPERTY(EditAnywhere, Category = See)
class UPawnSensingComponent* Sight;
// Sets default values
AAIBlogCharacter::AAIBlogCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
AIControllerClass = AAIBlogController::StaticClass();
Sight = CreateDefaultSubobject<UPawnSensingComponent>(TEXT("Sight"));
}
此时,我们的AI便拥有了控制其移动的controller,也有了"视力"的能力,
接着,为我们的Controller添加成员UBehaviorTreeComponent和UBehaviorTree,并在构造函数中生成,寻找我们编辑器中创建的行为树资源,如下所示:
class UBehaviorTreeComponent* BehaviorTreeCompo;
class UBehaviorTree* BehaviorTree;
public:
FORCEINLINE UBehaviorTreeComponent* GetBehaviorTreeCompo() { return BehaviorTreeCompo; }
AAIBlogController::AAIBlogController()
{
BehaviorTreeCompo = CreateDefaultSubobject<UBehaviorTreeComponent>(TEXT("BehaviorTree"));
static ConstructorHelpers::FObjectFinder<UBehaviorTree> BehaviorTreeAssert(TEXT("/Game/ThirdPersonCPP/AI/AIBlogBehaviorTree")); // 找到编辑器中的行为树
if (BehaviorTreeAssert.Succeeded())
{
BehaviorTree = BehaviorTreeAssert.Object; // 分配给tree
}
}
为了使我们的黑板资源能够持续更新数据,需要在AICharacter中,添加黑边资源,如下所示:
public:
class UBlackboardData* HeroData;
在面向对象的思想中,这个HeroData应该使私有的,并且有setter和getter函数,这里我就简化一下,直接设置访问权限为public。我们在Controller中,重写我们的possess函数,让我们的AI在被Controller控制的时候,就运行我们在编辑器中设置的行为树,并且初始话我们的AICharacter的黑板资源,如下所示:
void AAIBlogController::Possess(APawn* InPawn)
{
AAIBlogCharacter* AIC = Cast<AAIBlogCharacter>(InPawn);
if (AIC == nullptr)
{
return;
}
Super::Possess(InPawn);
if (BehaviorTreeCompo != nullptr)
{
if (BehaviorTree != nullptr)
{
BehaviorTreeCompo->StartTree(*BehaviorTree); // 运行行为树
AIC->HeroData = BehaviorTree->BlackboardAsset; // 设置黑板资源,方便以后更新黑板资源成员数据
}
}
}
此文就先讲到这里,下面的篇章将介绍行为树的节点,比如任务节点,使我们的AI能够追逐我们的任务。