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随机移动

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UE4中,你可以使用蓝图或C++来生成AI角色。下面是一种使用C++生成AI角色的方法: 1. 创建一个继承自AIController的C++类,用于控制AI角色的行为。例如,创建一个名为MyAIController的类: ```cpp // MyAIController.h #include "CoreMinimal.h" #include "AIController.h" #include "MyAIController.generated.h" UCLASS() class YOURPROJECT_API AMyAIController : public AAIController { GENERATED_BODY() public: // 构造函数 AMyAIController(); // 在BeginPlay中生成AI角色 virtual void BeginPlay() override; }; ``` 2. 在MyAIController.cpp文件中实现构造函数和BeginPlay函数,并在BeginPlay函数中生成AI角色。例如,使用SpawnActor函数生成AI角色: ```cpp // MyAIController.cpp #include "MyAIController.h" #include "YourAIClass.h" // 替换成你自己的AI角色类 AMyAIController::AMyAIController() { // 设置默认Pawn类 static ConstructorHelpers::FClassFinder<APawn> PawnClass(TEXT("Class'/Script/YourProject.YourAIClass'")); if (PawnClass.Class != nullptr) { DefaultPawnClass = PawnClass.Class; } } void AMyAIController::BeginPlay() { Super::BeginPlay(); // 在这里生成AI角色 GetWorld()->SpawnActor<AYourAIClass>(AYourAIClass::StaticClass(), FVector(0.0f, 0.0f, 0.0f), FRotator::ZeroRotator); } ``` 3. 在UE4编辑器中,创建一个AIController的子类蓝图,并将该蓝图指定给你的AI角色。 4. 在关卡中放置一个AIController的子类蓝图,并确保它具有与MyAIController对应的类。 通过以上步骤,你可以使用C++生成AI角色。根据你的需求,你可以在生成AI角色时设置不同的位置、旋转和其他属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值