행동트리 시스템
- 행동트리는 NPC가 해야 할 행동을 분석하고 우선순위가 높은 행동부터 NPC가 실행할 수 있도록 트리 구조로 설계하는 기법
- 블랙보드 애샛, 비헤이비어트리 에셋 을 생성
- 위 2개를 C++ 코드를 사용할라면 'AIModule' 모듈을 추가해야한다
//////////////h
UCLASS()
class ARENABATTLE_API AABAIController : public AAIController
{
GENERATED_BODY()
public:
AABAIController();
virtual void OnPossess(APawn* InPawn) override;
private:
UPROPERTY()
class UBehaviorTree* BTAsset;
UPROPERTY()
class UBlackboardData* BBAsset;
};
/////////////////cpp
#include "ABAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardData.h"
AABAIController::AABAIController()
{
static ConstructorHelpers::FObjectFinder<UBlackboardData> BBObject(TEXT("/Game/Book/AI/BB_ABCharacter.BB_ABCharacter"));
if (BBObject.Succeeded())
{
BBAsset = BBObject.Object;
}
static ConstructorHelpers::FObjectFinder<UBehaviorTree> BTObject(TEXT("/Game/Book/AI/BT_ABCharacter.BT_ABCharacter"));
if (BTObject.Succeeded())
{
BTAsset = BTObject.Object;
}
}
void AABAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
if (UseBlackboard(BBAsset, Blackboard))
{
Blackboard->SetValueAsVector(HomePosKey, InPawn->GetActorLocation());
if (!RunBehaviorTree(BTAsset))
{
ABLOG(Error, TEXT("AIController couldn't run behavior tree!"));
}
}
}
- NPC 순찰기능을 구현하려면 2가지 데이터가 필요하다
- NPC가 생성됐을 떄의 위치값, Vector 타입으로 키를 생성하고 HomePos
- NPC가 순찰할 위치정보를 보관할 키, Vector 타입으로 PatroPos
- 일단 블랙보드에 추가
- 앞으로 관련 키 이름이 절대 변하지 않는다근 가정하에 static const 를 사용해 변수 초기 값을 지정함. 이렇게 선언하면 참조하기 편하지만, 하드코딩으로 값을 변경해야 하는 단점이 있다.
//h
UCLASS()
class ARENABATTLE_API AABAIController : public AAIController
{
...........
static const FName HomePosKey;
static const FName PatrolPosKey;
}
///////////cpp
#include "BehaviorTree/BlackboardComponent.h"
const FName AABAIController::HomePosKey(TEXT("HomePos"));
const FName AABAIController::PatrolPosKey(TEXT("PatrolPos"));
void AABAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
if (UseBlackboard(BBAsset, Blackboard))
{
Blackboard->SetValueAsVector(HomePosKey, InPawn->GetActorLocation());
if (!RunBehaviorTree(BTAsset))
{
ABLOG(Error, TEXT("AIController couldn't run behavior tree!"));
}
}
}
- 사용하기 위해 모듈에 "GameplayTasks" 추가한다.
- 다음으로 NPC가 이동할 위치인 PatrolPos 데이터를 생성해야 한다. 이는 순찰할 때마다 바뀌므로 테스트를 제작해 행동트리에서 블랙보드에 값을 쓰도록 설계하는 것이 좋다
- BTTaskNode를 부모 클래스로 하는 BTTask_FindPatrolPos클래스를 생성한다
- UI 에서 표현할 떄는 BTTask_ 접두사 부분이 자동으로 걸러진다
행동트리는 태스크를 실행할때, ExecuteTask라는 멤버 함수를 실행하고, 함수는 다음의 셋중 하나의 값을 반환한다
Aborted : 태스크 실행 중에 준단됐다. 결과적으로 실패
Failed : 태스크를 수행했지만 실패
Succeeded : 태스크를 성공적으로 수행
InProgress : 대스크를 계속 수행하고 있다. 태크스의 실행 결과는 향후 얄려줌
* 그래서 ExeCuteTask 함수에서 다음 정찰 지점을 찾는 로직을 구현하고 바로 실행 결과를 반환라도록 구현한다. 태스크의 이름을 다른 이름으로 표시하고 싶다면 NodeName속성을 다른값으로 지정하면 된다
//h
//h
#include "CoreMinimal.h"
#include "BehaviorTree/BTTaskNode.h"
#include "BTTask_FindPatrolPos.generated.h"
UCLASS()
class ARENABATTLE_API UBTTask_FindPatrolPos : public UBTTaskNode
{
GENERATED_BODY()
public:
UBTTask_FindPatrolPos();
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
////cpp
#include "BTTask_FindPatrolPos.h"
#include "ABAIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "NavigationSystem.h"
UBTTask_FindPatrolPos::UBTTask_FindPatrolPos()
{
NodeName = TEXT("KKB_FindPatrolPos");
}
EBTNodeResult::Type UBTTask_FindPatrolPos::ExecuteTask(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory)
{
EBTNodeResult::Type Result = Super::ExecuteTask(OwnerComp, NodeMemory);
auto ControllingPawn = OwnerComp.GetAIOwner()->GetPawn();
if (nullptr == ControllingPawn)
return EBTNodeResult::Failed;
UNavigationSystemV1* NavSystem = UNavigationSystemV1::GetNavigationSystem(ControllingPawn->GetWorld());
if (nullptr == NavSystem)
return EBTNodeResult::Failed;
FVector Origin = OwnerComp.GetBlackboardComponent()->GetValueAsVector(AABAIController::HomePosKey);
FNavLocation NextPatrol;
if (NavSystem->GetRandomPointInNavigableRadius(FVector::ZeroVector, 500.0f, NextPatrol))
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(AABAIController::PatrolPosKey, NextPatrol.Location);
return EBTNodeResult::Succeeded;
}
return EBTNodeResult::Failed;
}
Secter 가 아닌 Sequence (뻘짓 5시간)
'Unreal > Game 1 (C++)' 카테고리의 다른 글
19. AI 컨트롤러와 행동트리 4 (공격) (0) | 2019.05.08 |
---|---|
19. AI 컨트롤러와 행동트리 3 (추격) (0) | 2019.05.08 |
19. AI 컨트롤러와 행동트리 1 + 네비시스템 (0) | 2019.05.08 |
18.UI와 데이터의 연동 (1) | 2019.05.08 |
17.모듈과 빌드 설정 (UI작업중) (0) | 2019.05.08 |