当前位置:   article > 正文

UEC++学习(十一)AI行为树

UEC++学习(十一)AI行为树

目录

 初步创建

创建Task使AI在随机点移动


 初步创建

首先创建AI类和AIController类,这里的Ai是直接继承的Character类,

在AI类中添加一个行为树变量

  1. class UBehaviorTree;
  2. UCLASS()
  3. class SHOOTTHEMUP_API ASTUAICharacter : public ASTUBaseCharacter
  4. {
  5. GENERATED_BODY()
  6. public:
  7. ASTUAICharacter(const FObjectInitializer& ObjInit);
  8. public:
  9. UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "AI")
  10. UBehaviorTree* BehaviorTreeAsset;
  11. };

在构造函数中:

  1. #include "AI/STUAIController.h"
  2. ASTUAICharacter::ASTUAICharacter(const FObjectInitializer& ObjInit): Super(ObjInit)
  3. {
  4. AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
  5. AIControllerClass = ASTUAIController::StaticClass();
  6. //为了AI在转向时能够平滑过渡,而不是直接硬切换
  7. //这一步非必须
  8. bUseControllerRotationYaw = false;
  9. if (GetCharacterMovement())
  10. {
  11. GetCharacterMovement()->bUseControllerDesiredRotation = true;
  12. GetCharacterMovement()->RotationRate = FRotator(0.0f, 200.0f, 0.0f);
  13. }
  14. }

上面操作在蓝图中,因为这里的ai暂时是直接放置在level的

然后创建一个行为树蓝图和黑板

将C++中创建的BehaviorTreeAsset变量赋值

然后在AIController,h中重载OnPossess函数,这个函数用于AI被拥有时调用

  1. public:
  2. virtual void OnPossess(APawn* InPawn) override;

在AIController.cpp

RunBehaviorTree:

  1. #include "AI/STUAICharacter.h"
  2. void ASTUAIController::OnPossess(APawn* InPawn)
  3. {
  4. Super::OnPossess(InPawn);
  5. const ASTUAICharacter* STUCharacter = Cast<ASTUAICharacter>(InPawn);
  6. if (STUCharacter)
  7. {
  8. RunBehaviorTree(STUCharacter->BehaviorTreeAsset);
  9. }
  10. }

对应蓝图函数;

创建Task使AI在随机点移动

创建一个Task类命名为STUNextLocation,继承BTTaskNode类

在构建文件中添加GameplayTasks和NavigationSystem模块

在STUNextLocation.h文件

FBlackboardKeySelector 、重载ExecuteTask函数  

meta = (EditCondition = "!SelfCenter"):当SelfCenter为false时,才启用CenterActorKey变量

  1. public:
  2. USTUNextLocationTask();
  3. virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory);
  4. protected:
  5. //随机生成点范围
  6. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
  7. float Radius = 1000.0f;
  8. //用于AI需要移动到的位置
  9. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
  10. FBlackboardKeySelector AimLocationKey;
  11. //用于处理攻击玩家时,移动到玩家范围内的点,而不是直接移动到玩家面前
  12. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
  13. bool SelfCenter = true;
  14. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI",meta = (EditCondition = "!SelfCenter"))
  15. FBlackboardKeySelector CenterActorKey;

在STUNextLocation.cpp中:

GetOwner()、GetPawn()

GetBlackboardComponent():获取黑板组件

UNavigationSystemV1::GetCurrent(Pawn):获得当前的Navi系统

GetRandomReachablePointInRadius():

SetValueAsVector():

GetValueAsObject():

  1. #include "BehaviorTree/BlackboardComponent.h"
  2. #include "AIController.h"
  3. #include "NavigationSystem.h"
  4. USTUNextLocationTask::USTUNextLocationTask()
  5. {
  6. //任务节点命名,随意设置
  7. NodeName = "Next Location";
  8. }
  9. EBTNodeResult::Type USTUNextLocationTask::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
  10. {
  11. AAIController* Controller = Cast<AAIController>(OwnerComp.GetOwner());
  12. UBlackboardComponent* Blackboard = OwnerComp.GetBlackboardComponent();
  13. if (!Controller || !Blackboard)
  14. {
  15. return EBTNodeResult::Failed;
  16. }
  17. APawn* Pawn = Controller->GetPawn();
  18. if (!Pawn)
  19. {
  20. return EBTNodeResult::Failed;
  21. }
  22. //获得当前的Navi系统
  23. UNavigationSystemV1* NavSys = UNavigationSystemV1::GetCurrent(Pawn);
  24. if (!NavSys)
  25. {
  26. return EBTNodeResult::Failed;
  27. }
  28. FNavLocation NavLocation;
  29. //AI位置
  30. FVector PawnLocation = Pawn->GetActorLocation();
  31. //用于检测到角色之后,变成以角色为原点,radius范围内随机生成一个点
  32. //SelfCenter为true,则以AI自己为原点,为false则以检测到的角色为原点
  33. if (!SelfCenter)
  34. {
  35. AActor* CenterActor = Cast<AActor>(Blackboard->GetValueAsObject(CenterActorKey.SelectedKeyName));
  36. if (!CenterActor)
  37. {
  38. return EBTNodeResult::Failed;
  39. }
  40. PawnLocation = CenterActor->GetActorLocation();
  41. }
  42. //判断 NavLocation是否在以PawnLocation为原点,半径为Radius的范围内
  43. bool Found = NavSys->GetRandomReachablePointInRadius(Pawn->GetActorLocation(), Radius, NavLocation);
  44. if (!Found)
  45. {
  46. return EBTNodeResult::Failed;
  47. }
  48. Blackboard->SetValueAsVector(AimLocationKey.SelectedKeyName, NavLocation.Location);
  49. return EBTNodeResult::Succeeded;
  50. }

SetValueAsVector在蓝图中对应的函数:

然后在行为树蓝图中执行这个任务:

Sequence:从左往右执行任务

找到C++中创建的任务

再创建一个MoveTo任务,作用和蓝图的AIMoveTo函数差不多

然后在黑板蓝图中创建一个Vector变量,命名为AimLocation

选中刚刚创建的NextLocation任务,将C++中创建的AimLocationKey对应的值改为黑板中创建的AimLocaion变量

然后选择MoveTo任务,将BlackboardKey值改为AimLocation

在关卡中添加NavMeshBoundsVolume,绿色区域表示Ai能够移动的范围,不加这个Actor的话,AI是不会移动的,按P键可以隐藏绿色范围

最终效果:

按下键盘的 " 键,可以查看Ai的调试信息

Ai随机移动

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/336345
推荐阅读
相关标签
  

闽ICP备14008679号