[언리얼 입문] BehaviorTree #1
이번엔 Behaivor Tree를 사용한 AI 구현에 대해 실습해봤다.
유니티에서는 에셋으로 샘플정도만 사용해봤는데 언리얼은 해당툴이 기본으로제공이된다.
Behavior Tree를 사용하기위해선 먼저 BlackBoard와 BehaviorTree 파일을 하나씩 생성해줘야한다.
이후 사용하기 위해서는 이전에 만들었던 AI컨트롤러에 OnPossess를 수정해줘야하는데
//AI컨트롤 헤더
UPROPERTY()
class UBehaviorTree* BehaviroTree;
UPROPERTY()
class UBlackboardData* BlackboardData;
//AI컨트롤 CPP
void AMyAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
//기존
//GetWorld()->GetTimerManager().SetTimer(TimerHandle,this,&AMyAIController::RandomMove,3.f,true);
//비헤이비어트리
if(UseBlackboard(BlackboardData,Blackboard))
{
if(RunBehaviorTree(BehaviroTree))
{
}
}
}
이런식으로 BehaviorTree와 BlackBoardData에대한 정보를 추가하고 비헤이비어 트리를 실행하는 방식으로 필요하다.
이후에는 BehaviorTree 내부를 구성해야한다.
이전 랜덤이동과 동일한 동작을 하게하기위해 먼저 BlackBoard에 랜덤좌표를 저장하기위한 Vector타입 키를 하나 추가한다.
이후 BehaviorTree에 새노드를 추가하기위해 BTTaskNode를 상속받는 새 C++파일을 생성하여 새노드를 만들어줘야한다.
//랜덤좌표노드 헤더
UCLASS()
class UNREALTUTORIAL_API UBTTask_FindPatrolPos : public UBTTaskNode
{
GENERATED_BODY()
public:
UBTTask_FindPatrolPos();
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
//랜덤좌표노드 CPP
UBTTask_FindPatrolPos::UBTTask_FindPatrolPos()
{
NodeName = TEXT("FindPatrolPos");
}
EBTNodeResult::Type UBTTask_FindPatrolPos::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
EBTNodeResult::Type Result = Super::ExecuteTask(OwnerComp,NodeMemory);
auto CurrentPawn = OwnerComp.GetAIOwner()->GetPawn();
if(CurrentPawn == nullptr)
{
return EBTNodeResult::Failed;
}
UNavigationSystemV1* NavSystem = UNavigationSystemV1::GetNavigationSystem(GetWorld());
if(NavSystem == nullptr)
{
return EBTNodeResult::Failed;
}
FNavLocation RandomLocation;
//500범위 내에서 랜덤좌표
if(NavSystem->GetRandomPointInNavigableRadius(FVector::ZeroVector, 500.f, RandomLocation))
{
//UAIBlueprintHelperLibrary::SimpleMoveToLocation(this,RandomLocation);
OwnerComp.GetBlackboardComponent()->SetValueAsVector(FName(TEXT("PatrolPos")),RandomLocation.Location);
return EBTNodeResult::Succeeded;
}
return EBTNodeResult::Failed;
}
이렇게 노드 내용을 다채워줬으면 BehaviorTree를 구성해야한다.
실습을 모두 수강한뒤 상태라 이렇게되있지만 TargetOff는 원래 기본적으로 없는부분이고
FindPatrolPos가 위에서 새로만든 노드이다. 구성을 이렇게 해주면된다.
여기서 Wait과 MoveTo는 기본제공되는 노드로 이름보면 기능을 알수있고
위에 Sequence의 역할은 연결된 Task를 순차적으로 실행하는 노드라고 보면된다
연결된 자식Task중를 왼쪽부터 끝까지 순차적으로 실행하며 자식중 하나라도 실패하게되면 다시 처음으로되돌아간다.
Move To 노드의 Key를 이전에 만든 PatrolPos로 수정해줘야한다.
이상태로 게임을 실행하면 이제 5초 대기후 랜덤좌표로 자동으로 이동하는 AI가 된다.