favicon Jay Lee DevLog

728x90
300x250

이번 글에서는 블랙보드와 비헤이비어 트리를 이용하여,

AI를 구현해보려 한다.

이전 글에서 다 끝내려했는데, 하다보니 내용이 너무 길어질 것 같아서 이번 글에 정리하겠다.

 

시작하기에 앞서 이전 글에서 MyAIController에 작성한 소스는 모두 주석처리 해둬야 한다.

같은 내용이지만, 블랙보드와 비헤이비어 트리를 이용하여 같은 동작 + 추가적인 동작을 하도록 할 거기 때문이다.

먼저 시작에 앞서 모듈 추가를 해줘야 한다.

 

이제 시작해보자.

먼저 마우스 우클릭 메뉴에서

블랙보드와 밑에 있는 비헤이비어 트리를 만들어 준다.

그리고 블랙보드를 더블클릭하면 편집창이 생기는데,

위와 같이 새키를 눌러 앞에 색깔과 이름을 맞춰 추가해준다.

여기서 주의할 점은 이전 글에서

나중에 사용한다고 변수 3개를 추가해둔게 있는데, 그 이름과 같아야 한다.

const FName AMyAIController::HomePosKey(TEXT("HomePos"));
const FName AMyAIController::PatrolPosKey(TEXT("PatrolPos"));
const FName AMyAIController::TargetKey(TEXT("Target"));

 

그리고 주의해야할 점!

Target을 추가한 뒤에는 밑의 사진처럼 베이스 클래스를 MyCharacter로 해줘야 한다. 쫓아갈 목표를 설정해 주는거다.

이렇게 해두면, MyCharacter를 상속받은 모든 캐릭터들은 다 목표 대상이 된다.

이후 BTService를 상속하여 C++ 클래스를 만들어준다. 해당 클래스는 범위 내의 캐릭터를 찾았을 경우 Return해주는 클래스로 만드려한다.

이제 소스를 추가하자.

먼저 MyBTService_Detect.h에 아래 소스 추가.

public:
	UMyBTService_Detect();

protected:
	virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DetalSeconds) override;

MyBTService_Detect.cpp에 아래 소스 추가.

#include "MyAIController.h"
#include "MyCharacter.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "DrawDebugHelpers.h"

UMyBTService_Detect::UMyBTService_Detect()
{
	NodeName = TEXT("Detect");
	Interval = 1.0f;
}

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

	UE_LOG(LogTemp, Warning, TEXT("UMyBTService_Detect::TickNode %s"), *NodeName);

	APawn* ControllingPawn = OwnerComp.GetAIOwner()->GetPawn(); // Pawn 가져오기
	if (nullptr == ControllingPawn)
		return;

	UWorld* World = ControllingPawn->GetWorld(); // World 가져오기
	FVector Center = ControllingPawn->GetActorLocation(); // Centor 값 가져오기
	float DetectRadius = 600.0f; // 서칭할 범위

	if (nullptr == World)
		return;

	TArray<FOverlapResult> OverlapResults;						// 자기 자신은 제외.
	FCollisionQueryParams CollisionQueryParam(NAME_None, false, ControllingPawn);
	bool bResult = World->OverlapMultiByChannel(
		OverlapResults,
		Center,
		FQuat::Identity, // 회전하지 않는 값
		ECollisionChannel::ECC_GameTraceChannel1,
		FCollisionShape::MakeSphere(DetectRadius), // 몬스터 주위 서칭 범위 설정
		CollisionQueryParam
	);

	if (bResult)
	{
		for (auto const& OverlapResult : OverlapResults)
		{
			AMyCharacter* MyCharacter = Cast<AMyCharacter>(OverlapResult.GetActor()); // 다운캐스팅
			if (MyCharacter && MyCharacter->GetController()->IsPlayerController()) // 플레이어가 컨트롤 하는 MyCharacter만 처리
			{
				if (MyCharacter->CurrentHP > 0)
				{
					OwnerComp.GetBlackboardComponent()->SetValueAsObject(AMyAIController::TargetKey, MyCharacter); // 블랙보드 TargetKey에 값 셋팅
					DrawDebugSphere(World, Center, DetectRadius, 16, FColor::Green, false, 0.2f);

					DrawDebugPoint(World, MyCharacter->GetActorLocation(), 10.0f, FColor::Blue, false, 0.2f);
					DrawDebugLine(World, ControllingPawn->GetActorLocation(), MyCharacter->GetActorLocation(), FColor::Blue, false, 0.27f);
					return;
				}
			}
		}
	}

	OwnerComp.GetBlackboardComponent()->SetValueAsObject(AMyAIController::TargetKey, nullptr);
	DrawDebugSphere(World, Center, DetectRadius, 16, FColor::Red, false, 0.2f);
}

여기까지 추가한 후에, MyAIController를 상속받는 블루프린트를 하나 만들어준다

그리고 블루프린트에 아래와 같이 추가.

빨간색으로 표시된 부분은 자신이 만든 블랙보드와 비헤이비어 트리로 바꿔준다.

그리고 HomeKey의 경우,

위의 사진에 +부분을 눌러 만들 수 있다.

주의할 점은 기본 값을 HomePos와 연결한다.

 

이제 비헤이비어 트리를 수정해보자.

일단은 위와 같이 만들어 줄건데, 마우스 우클릭하시면 위의 필요한 부분들 다 찾을 수 있다.

한가지 유의할 점은 Detect의 경우 위에서 추가한 소스를 통해 만들어진 서비스라는 점이다.

추가로, 아래 사진처럼 블랙보드 에셋이 자기가 만든 블랙보드로 되어 있어야 한다.

여기까지 하고 플레이해보면,

처음에 범위 밖일때는 빨간색으로 표시되면 감지하지 못하다가,

범위 안으로 들어가면 감지하여 초록색으로 바뀌는걸 볼 수 있다.

여기서 아래와 같이 비헤이비어 트리를 수정하면,

범위 안으로 들어오면 따라가는 동작을 추가 할 수 있다.

TargetDetect처럼 파란 옵션들은 마우스 우클릭 메뉴에서 블랙보드를 추가한거다.

수정 후에 다시 플레이해보면,

범위 내 접근 시 따라오는 걸 확인 할 수 있다.

여기서 플레이어의 속도와 적 캐릭터의 속도가 같은데,

이 부분은 무브먼트를 검색해서 수정해주면 된다.

 

이제 좀 더 나아가서, 이전 글에서 추가했던 정찰범위를 추가하고,

공격범위 내에 접근하면 공격하도록 추가해보려 한다.

 

다음글에서 이어가보겠다.

 

 

728x90
반응형

+ Recent posts

/ /

Contact

📧 dlwjdwls60@naver.com


블로그에 내용이 있으면 해당 글을 보여주며, 없으면 내용이 복사된 채로 ChatGPT로 연결됩니다.