您现在的位置是:首页 >其他 >UE5.1.1C++从0开始(11.AI与行为树)网站首页其他

UE5.1.1C++从0开始(11.AI与行为树)

楚江_wog1st 2024-06-27 18:01:03
简介UE5.1.1C++从0开始(11.AI与行为树)

怕有些朋友不知道教程指的是哪一个,我在这里把教程的网址贴出来:https://www.bilibili.com/video/BV1nU4y1X7iQ?p=1

这一章开始进入电脑玩家逻辑的编写,因为是第一次接触,所以老师也没有讲什么很难的问题,这里还是老样子,直接上C++的代码

SAICharacter.h

这个对象类把输入给删除了,因为电脑对象不需要我们的输入以及输入事件绑定啥的。然后把相应的cpp文件的相应的函数删除就好。

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SAICharacter.generated.h"

UCLASS()
class ACTIONROGUELIKE_API ASAICharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ASAICharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};

然后是SAIController,我看完这一章后对这个controller的理解就是:用来运行我们所选择的行为树,同时给我们的黑板上的变量赋一个初值。

SAIController.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "AIModule/Classes/BehaviorTree/BehaviorTree.h"
#include "SAIController.generated.h"

/**
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API ASAIController : public AAIController
{
	GENERATED_BODY()
	
    //行为树
	UPROPERTY(EditDefaultsOnly)
	class UBehaviorTree* BehavioutTree;

protected:
	virtual void BeginPlay() override;
	
};

SAIController.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/SAIController.h"
#include "Kismet/GameplayStatics.h"
#include "BehaviorTree/BlackboardComponent.h"


void ASAIController::BeginPlay()
{
	Super::BeginPlay();
    
	//运行我们指定的行为树
	RunBehaviorTree(BehavioutTree);
	
    //gamestatics来获取我们的主玩家
	APawn* MyPawn = UGameplayStatics::GetPlayerPawn(this,0);
	if (ensure(MyPawn))
	{
        //给黑板内的变量赋初值
		GetBlackboardComponent()->SetValueAsVector("MoveToLocation", MyPawn->GetActorLocation());

		GetBlackboardComponent()->SetValueAsObject("TargectActor", MyPawn);
	}
}

再之后就是行为树的服务函数了,从UBTServices这个基类派生出来,说白了就是在蓝图编辑器里头写行为树的时候,你右键找‘服务’那一项下面可以找到我们自定义的服务函数。

SBTService_CheckAttackRange.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "BehaviorTree/BTService.h"
#include "SBTService_CheckAttackRange.generated.h"

/** 
 * 
 */
UCLASS()
class ACTIONROGUELIKE_API USBTService_CheckAttackRange : public UBTService
{
	GENERATED_BODY()

//黑板的属性,在蓝图编辑器内指定
protected:
	UPROPERTY(EditAnywhere,Category="AI")
	FBlackboardKeySelector AttackRangeKey;

//重写父类的函数
protected:
	virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};

SBTService_CheckAttackRange.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/SBTService_CheckAttackRange.h"
#include "AIModule/Classes/BehaviorTree/BlackboardComponent.h"
#include "AIModule/Classes/BehaviorTree/BehaviorTreeTypes.h"

#include "AIModule/Classes/AIController.h"

void USBTService_CheckAttackRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
	Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

	//检查ai和玩家间的距离
	UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();
	if (ensure(BlackboardComp))
	{
		AActor* TargetActor = Cast<AActor>(BlackboardComp->GetValueAsObject("TargetActor"));
		if (ensure(TargetActor))
		{
			AAIController* MyController = OwnerComp.GetAIOwner();
			if (ensure(MyController))
			{
				APawn* AIPawn = MyController->GetPawn();
				if (ensure(AIPawn))
				{
					float DistanceTo = FVector::Distance(TargetActor->GetActorLocation(), AIPawn->GetActorLocation());

					bool bWithinRange = DistanceTo < 2000.0f;

					bool bHasLineSight = false;

					if (bWithinRange)
					{
						bHasLineSight = MyController->LineOfSightTo(TargetActor);
					}
					

					BlackboardComp->SetValueAsBool(AttackRangeKey.SelectedKeyName , (bWithinRange&&bHasLineSight));
				}
			}
		}
	}
}

我们写的这个service在蓝图里头长这样:

请添加图片描述

可以看到有个Attack Range Key,这个就是我们在.h里头定义的那个blackboardkeyselector的变量。剩余的蓝图的内容以及创建对象绑定动画,创建C++的蓝图类啥的我就不在这里赘述了,教程讲的非常明确。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。