UE4中的AI和行为树(C++)
本篇文章用的是官网shooter示例项目,给大家讲解C++里怎么用AI和行为树,源码也看过一下,比较复杂,以后有空会贴出了,同样也是visio画的流程图
UBTDecorator_xxx详解
AXXXAIController详解
AshooterBot类
AI的行动主要逻辑位于BehaviorTree内,AI的主要行动实现主要位于AIController中,而AI的记忆主要位于Blackboard内。下面是一些基本概念:
1.BehaviorTree内部含有一个成员是Blackboard。所以我们一般只给一个AICharacter内部设置一个成员BehaviorTree就行了,而在Editor内把Blackboard指认给BehaviorTree。
2.Editor内的Blackboard实际上是一个UBlackboardData,而不是一个Component,BehaviorTree内部的Blackboard成员是UBlackboardData。Component用于AIController内,在AIController我们会声明一个UBlackboardComponent,而在Editor里边创建的是一个UBlackboardData,是不一样的数据结构,UBlackboardComponent的初始化函数InitializeBlackboard接受一个参数是UBlackboardData。
3.UBlackboardData是初始化UBlackboardComponent的参数数据,而我们之后的操作主要在UBlackboardComponent上完成。比如UBlackboardComponent的函数SetValueAsVector就是给Blackboard上的一个Vector参数赋值。
4.BehaviorTree和Blackboard比较类似,也是有一个UBehaviorTree类型和一个UBehaviorTreeComponent类型,主要操作位于UBehaviorTreeComponent上,UBehaviorTree内只是数据。比如UBehaviorTreeComponent的一个函数是StartTree,而参数是UBehaviorTree。
5.可见Component一般实现逻辑,而需要用到的数据都是另一种类型。我们一般把数据部分,就是UBehaviorTree和UBlackboardData放在Character中,而把对应的两个Component放在AIController中,每次使用AIController调用自己Pawn内部的UBlackboardData和UBehaviorTree。这样就可以把操作和数据分离,达到Controller的复用。
6.需要使用UBehaviorTreeComponent或者UBlackboardComponent的地方需要添加必要的头文件。
/* AI Specific includes */ #include "BehaviorTree/BehaviorTree.h" #include "BehaviorTree/BehaviorTreeComponent.h" #include "BehaviorTree/BlackboardComponent.h"
这比较奇怪,因为直接声明Component是可以识别的,但是声明是不完整的,大概是因为默认include里边只有class声明没有实现吧。因为class有声明只是没实现,所以这些include可以加到cpp里,不用加到h里。遇到类型不完整都可以试试加入相应头文件来解决。
还要注意一点,要更改控制build的c#文件里代码,加一个AIModule进去,这样UE在build的时候才会把AI相关模块build进去。加了这一个模块之后,build时间也显著增加了。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AIModule" });
下面介绍一下AI逻辑和记忆的编程方法:
1.在Editor内创建AIController,AICharacter,BehaviorTree,Blackboard文件,并把Blackboard指认给BehaviorTree内部的存储字段,把AIController指认给AICharacter作为操纵者。
2.首先在AICharacter内声明一个UBehaviorTree字段,注意UBlackboardData是包含在内部的。然后在Editor里边给他指认一个BehaviorTree。
3.在AIController内部声明两个UBlackboardComponent和UBehaviorTreeComponent字段。
4.初始化两个Component字段,首先使用CreateDefaultSubobject初始化内存,之后使用
//初始化UBlackboardComponent,把他和一个UBlackboardData联系起来。UBlackboardData取自Pawn的BehaviorTree的内部。 BlackboardComp->InitializeBlackboard(*GetPawn()->BehaviorTree->UBlackboardData); //UBehaviorTreeComponent不需要initialize,可以直接start一个Tree,参数就是你要start的tree,当然就是Pawn的那个字段了 BehaviorComp->StartTree(*GetPawn()->BehaviorTree);5.之后如果AI的记忆要更变,就对UBlackboardComponent进行操作,它会对自己连接的Blackboard进行更改
//这里更改了一个Blackboard内部的Vector参数,作为AI跟踪的目的地。 BlackboardComp->SetValueAsVector(FName(“TargetLocation”), XXX->GetActorLocation());
6.AI的初始化和记忆更新写好之后,就是写AI逻辑的时候了,这关系到Editor里的BehaviorTree文件。BehaviorTree文件的编程方法和Blueprint类似,都是node连pin的。