기타/Unreal

[Unreal C++] Behavior Tree 5 (데코레이터 사용하기)

푸쿠이 2021. 5. 12. 14:49
참고 문서

책 '이득우의 언리얼 C++ 게임 개발의 정석' Chapter 12

&

docs.unrealengine.com/ko/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeNodeReference/index.html

 

데코레이터 노드란?

언리얼 문서에 이렇게 설명되어있다.

Also known as conditionals.
These attach to another node and
make decisions on whether or not a branch in the tree,
or even a single node, can be executed.

// 번역해보면
조건부로도 알려져 있습니다.
다른 노드에 연결되고
해당 노드에 대한 결정을 내립니다.
단일 노드도 실행할 수 있습니다.

노드가 실행이 될지 말지 결정하는 조건문 같은 노드이다.

 

데코레이터 노드 사용하기

데코레이터 노드 중에서 만들어져있는 Blackboard 노드를 통해 조건문을 쉽게 만들 수 있다.

Target이 있다면, (= Target Is Set)

Target이 없다면, (= Target Is Not Set)

으로 설정하면 된다.

키 값이 변경되면 현재 노드의 실행을 즉시 멈출 것이라면, (= OnValueChange, Self)

으로 설정하면 된다.

 

데코레이터 노드 만들기

BTDecorator를 부모 클래스로 하는 클래스를 생성한다.

클래스명은 BTDecorator_IsInAttackRange로 했다.

 

이 클래스에는 거리를 체크하는 기능을 만들 것이다.

 

데코레이터 노드 클래스

CalculateRawConditionValue() 함수를 오버라이딩해서 구현한다.

이 함수는 const로 선언돼 데코레이터 클래스의 멤버 변수 값은 변경할 수 없다.

UCLASS()
class ARENABATTLE_API UBTDecorator_IsInAttackRange : public UBTDecorator
{
	GENERATED_BODY()

protected:
	virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const override;
};

 

데코레이터 노드 내용 구현하기
#pragma once

#include "ArenaBattle.h"
#include "BehaviorTree/BTDecorator.h"
#include "BTDecorator_IsInAttackRange.generated.h"

UCLASS()
class ARENABATTLE_API UBTDecorator_IsInAttackRange : public UBTDecorator
{
	GENERATED_BODY()
	
public:
	UBTDecorator_IsInAttackRange();

protected:
	virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const override;
};
#include "BTDecorator_IsInAttackRange.h"
#include "ABAIController.h"
#include "ABCharacter.h"
#include "BehaviorTree/BlackboardComponent.h"

UBTDecorator_IsInAttackRange::UBTDecorator_IsInAttackRange()
{
	NodeName = TEXT("CanAttack");
}

bool UBTDecorator_IsInAttackRange::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
	APawn* ControllingPawn = OwnerComp.GetAIOwner()->GetPawn();
	if (nullptr == ControllingPawn) return false;

	AABCharacter* Target = Cast<AABCharacter>(OwnerComp.GetBlackboardComponent()->GetValueAsObject(AABAIController::Key_Target));
	if (nullptr == Target) return false;

	bool bResult = (Target->GetDistanceTo(ControllingPawn) <= 200.0f);
	return bResult;
}

Inversed를 체크하면, Bool 값이 반대로 동작하게 만들 수 있다.