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

目录

 初步创建

创建Task使AI在随机点移动


 初步创建

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

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

class UBehaviorTree;

UCLASS()
class SHOOTTHEMUP_API ASTUAICharacter : public ASTUBaseCharacter
{
	GENERATED_BODY()

public:
	ASTUAICharacter(const FObjectInitializer& ObjInit);
	
public:

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "AI")
		UBehaviorTree* BehaviorTreeAsset;
};

在构造函数中:

#include "AI/STUAIController.h"

ASTUAICharacter::ASTUAICharacter(const FObjectInitializer& ObjInit): Super(ObjInit)
{

	AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
	AIControllerClass = ASTUAIController::StaticClass();

    //为了AI在转向时能够平滑过渡,而不是直接硬切换
    //这一步非必须
	bUseControllerRotationYaw = false;
	if (GetCharacterMovement())
	{
		GetCharacterMovement()->bUseControllerDesiredRotation = true;
		GetCharacterMovement()->RotationRate = FRotator(0.0f, 200.0f, 0.0f);
	}

}

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

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

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

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

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

在AIController.cpp

RunBehaviorTree:

#include "AI/STUAICharacter.h"


void ASTUAIController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);
	const ASTUAICharacter* STUCharacter = Cast<ASTUAICharacter>(InPawn);
	if (STUCharacter)
	{
		RunBehaviorTree(STUCharacter->BehaviorTreeAsset);
	}
}

对应蓝图函数;

创建Task使AI在随机点移动

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

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

在STUNextLocation.h文件

FBlackboardKeySelector 、重载ExecuteTask函数  

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

public:
	USTUNextLocationTask();

	virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory);

protected:
    //随机生成点范围
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
		float Radius = 1000.0f;
    //用于AI需要移动到的位置
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
		FBlackboardKeySelector AimLocationKey;

	//用于处理攻击玩家时,移动到玩家范围内的点,而不是直接移动到玩家面前
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
		bool SelfCenter = true;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI",meta = (EditCondition = "!SelfCenter"))
		FBlackboardKeySelector CenterActorKey;

在STUNextLocation.cpp中:

GetOwner()、GetPawn()

GetBlackboardComponent():获取黑板组件

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

GetRandomReachablePointInRadius():

SetValueAsVector():

GetValueAsObject():

#include "BehaviorTree/BlackboardComponent.h"
#include "AIController.h"
#include "NavigationSystem.h"

USTUNextLocationTask::USTUNextLocationTask()
{
    //任务节点命名,随意设置
	NodeName = "Next Location";
}

EBTNodeResult::Type USTUNextLocationTask::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	AAIController* Controller = Cast<AAIController>(OwnerComp.GetOwner());
	UBlackboardComponent* Blackboard = OwnerComp.GetBlackboardComponent();
	if (!Controller || !Blackboard)
	{
		return EBTNodeResult::Failed;
	}

	APawn* Pawn = Controller->GetPawn();
	if (!Pawn)
	{
		return EBTNodeResult::Failed;
	}

	//获得当前的Navi系统
	UNavigationSystemV1* NavSys = UNavigationSystemV1::GetCurrent(Pawn);
	if (!NavSys)
	{
		return EBTNodeResult::Failed;
	}

	FNavLocation NavLocation;
	//AI位置
	FVector PawnLocation = Pawn->GetActorLocation();

	//用于检测到角色之后,变成以角色为原点,radius范围内随机生成一个点
	//SelfCenter为true,则以AI自己为原点,为false则以检测到的角色为原点
	if (!SelfCenter)
	{
		AActor* CenterActor = Cast<AActor>(Blackboard->GetValueAsObject(CenterActorKey.SelectedKeyName));
		if (!CenterActor)
		{
			return EBTNodeResult::Failed;
		}
		PawnLocation = CenterActor->GetActorLocation();
	}

	//判断 NavLocation是否在以PawnLocation为原点,半径为Radius的范围内
	bool Found = NavSys->GetRandomReachablePointInRadius(Pawn->GetActorLocation(), Radius, NavLocation);
	if (!Found)
	{
		return EBTNodeResult::Failed;
	}

	Blackboard->SetValueAsVector(AimLocationKey.SelectedKeyName, NavLocation.Location);
	return EBTNodeResult::Succeeded;

}

SetValueAsVector在蓝图中对应的函数:

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

Sequence:从左往右执行任务

找到C++中创建的任务

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

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

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

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

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

最终效果:

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

Ai随机移动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值