目录
服务是可以添加到行为树节点的特殊类,具有自己的Tick功能,可以在里面写游戏逻辑,并且还能够更改黑板上的键
这里主要是对UEC++学习(十一)和(十二)中的AI随机移动和追击玩家逻辑进行优化。如果不感兴趣的话可以直接跳转到第二步
创建BTService类,命名为STUFindEnemyService
(1)优化逻辑
在STUFindEnemyService.h中创建一个FBlackboardSelector变量,用于存储Ai感知组件寻找到的角色,重载TickNode函数
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI") FBlackboardKeySelector EnemyActorKey; virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
在STUFindEnemyService.cpp中
GetBlackboardComponent():获得黑板组件
GetAIOwner():获得AiController
SetValueAsObject:将actor赋值给EnemyActorKey
#include "STUUtil.h" #include "BehaviorTree/BlackboardComponent.h" #include "AIController.h" #include "Components/STUAIPerceptionComponent.h" void USTUFindEnemyService::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) { UBlackboardComponent* Blackboard = OwnerComp.GetBlackboardComponent(); if (Blackboard) { AAIController* Controller = OwnerComp.GetAIOwner(); //这是获得AI感知组件,是我自己写的模板类 USTUAIPerceptionComponent* PerceptionComponent = STUUtil::GetSTUPlayerComponent<USTUAIPerceptionComponent>(Controller); if (PerceptionComponent) { //将蓝图key对应的值改为ai找到的角色 //GetClosestEnemy():可以在C++学习(十二)中查看具体逻辑 Blackboard->SetValueAsObject(EnemyActorKey.SelectedKeyName, PerceptionComponent->GetClosestEnemy()); } } Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds); }
在AIController.h中,新建一个FName变量,用于获取上面逻辑用SetValueAsObject设置的Actor
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI") FName FocusOnKeyName = "EnemyActor"; AActor* GetFocusOnActor() const;
在AIController.cpp中
GetBlackboardComponent()->GetValueAsObject()
void ASTUAIController::Tick(float DeltaTime) { Super::Tick(DeltaTime); AActor* AimActor = GetFocusOnActor(); SetFocus(AimActor); } AActor* ASTUAIController::GetFocusOnActor() const { if (GetBlackboardComponent()) { //返回黑板中参数和FocusOnKeyName同名参数对应的值 return Cast<AActor>(GetBlackboardComponent()->GetValueAsObject(FocusOnKeyName)); } return nullptr; }
(2)使用AI Service
在黑板蓝图中创建一个变量用于存储感知组件寻找到的角色,命名和AIController中的FocusOnKeyName对应值一样
在行为树蓝图中添加一个Selector选择器节点,从左往右执行,当左边不满足执行条件之后就会执行右边
在选择器中添加服务,因为FindEnemy这个逻辑是需要一直检测的,所以这一开始的选择器中添加。
将EnemyActorKey对应的值改为黑板中的变量
创建两个序列,一个用于检测到角色之后攻击角色,一个用于AI丢失角色视野后随机移动,分别修改命名为Attack和随机移动。
添加NextLocation和MoveTo两个任务,NextLocation任务的实现逻辑在C++学习(十一)中,修改NextLocation和MoveTO相关的参数
添加两个装饰器,选择黑板类型,目的是当Ai在执行随机移动逻辑时,检测到角色后,停止执行随机移动。有点类似于if语句。
分别修改两个装饰器的参数
最终效果:
按 “ 键查看AI调试信息,按下 4 可以查看感知组件信息
追击角色以及巡逻