본문 바로가기
포트폴리오 제작/Project_P

Project_P 행동트리 모델 생성

by k99812 2024. 11. 14.

언리얼 AI 종류


 

  • Behavior Tree
    • 행동트리 모델
  • Blackboard
    • 인공지능 모델에서 의사결정을 하기 위한
      기본 데이터를 제공해주는 데이터 저장소
    • 행동트리에서 필요한 변수(데이터)를 관리
  • Evironment Query
    • 행동트리에서 호출되어 환경으로부터 데이터를 수집하는데 사용

블랙보드
행동트리

AI컨트롤러에 행동트리 적용


AIController를 상속받아 APPAIController클래스 생성

 

APPAIController 헤더파일

#include "CoreMinimal.h"
#include "AIController.h"
#include "PPAIController.generated.h"

/**
 * 
 */
UCLASS()
class PROJECT_P_API APPAIController : public AAIController
{
	GENERATED_BODY()
	
public:
	APPAIController();

	void RunAI();
	void StopAI();

protected:
	//컨트롤러가 폰에 빙의할때 실행되는 함수
	virtual void OnPossess(APawn* InPawn) override;

private:
	UPROPERTY()
	TObjectPtr<class UBlackboardData> BBAsset;

	UPROPERTY()
	TObjectPtr<class UBehaviorTree> BTAsset;
};

 

  • APPAIController();
    • 생성자
  • void RunAI();
    void StopAI();
    • RunAI, StopAI 함수를 생성
  • virtual void OnPossess(APawn* InPawn) override;
    • 컨트롤러가 폰에 빙의할때 실행되는 함수
    • 부모클래스에서 상속받음
  • UPROPERTY()
    TObjectPtr<class UBlackboardData> BBAsset;

    UPROPERTY()
    TObjectPtr<class UBehaviorTree> BTAsset;
    • 에디터에서 생성한 블랙보드, 행동트리를 저장할 변수

 

APPAIController Cpp파일

생성자

APPAIController::APPAIController()
{
	//#include "BehaviorTree/BlackboardData.h"추가
	static ConstructorHelpers::FObjectFinder<UBlackboardData> BlackboardRef(TEXT("/Script/AIModule.BlackboardData'/Game/Project_P/AI/BB_PPCharacter.BB_PPCharacter'"));
	if (BlackboardRef.Object)
	{
		BBAsset = BlackboardRef.Object;
	}

	//#include "BehaviorTree/BehaviorTree.h"추가
	static ConstructorHelpers::FObjectFinder<UBehaviorTree> BTAssetRef(TEXT("/Script/AIModule.BehaviorTree'/Game/Project_P/AI/BT_PPCharacter.BT_PPCharacter'"));
	if(BTAssetRef.Object)
	{
		BTAsset = BTAssetRef.Object;
	}
}

 

  • ConstructorHelpers에 Finder함수를 통해 행동트리와 블랙보드를 가져옴
  • "BehaviorTree/BlackboardData.h", "BehaviorTree/BehaviorTree.h" 헤더를 추가

RunAI

void APPAIController::RunAI()
{
	//부모 클래스에 UBlackboardComponent가 저장되있음
	UBlackboardComponent* BBComponent = Blackboard.Get();
	if (UseBlackboard(BBAsset, BBComponent))
	{
		bool RunResult = RunBehaviorTree(BTAsset);
		ensure(RunResult);
	}
}

 

  • UBlackboardComponent* BBComponent = Blackboard.Get();
    • 부모클래스에 선언되어있는 블랙보드컴포넌트를 가져옴
  • if (UseBlackboard(BBAsset, BBComponent))
    • UseBlackboard(블랙보드데이터, 블랙보드컴포넌트)를 통해 가져온
      블랙보드애셋을 사용
    • 함수가 정상적으로 실행됐으면
      • bool RunResult = RunBehaviorTree(BTAsset);
        • 가져온 행동트리를 실행

StopAI

void APPAIController::StopAI()
{
	//UBehaviorTreeComponent는 BrainComponent의 자식 클래스
	//부모 클래스에 BrainComponent가 선언 되어있음
	UBehaviorTreeComponent* BTComponent = Cast<UBehaviorTreeComponent>(BrainComponent);
	if (BTComponent)
	{
		BTComponent->StopTree();
	}
}

 

  • UBehaviorTreeComponent* BTComponent = Cast<UBehaviorTreeComponent>(BrainComponent);
    • 부모 클래스에 BrainComponent가 선언 되어있음
    • UBehaviorTreeComponent는 BrainComponent의 자식 클래스
    • BrainComponent를 UBehaviorTreeComponent로 캐스트
      • RunBehaviorTree 함수에서 BrainComponent를 UBehaviorTreeComponent로 대입함
        • BrainComponent = BTComp;
    • if (BTComponent)
      • 캐스팅이 성공했으면
      • BTComponent->StopTree();
        • 행동트리를 멈춤

 

OnPossess

void APPAIController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);

	RunAI();
}

 

  • Super::OnPossess(InPawn);
    • 부모함수 실행
  • RunAI();
    • AI 컨트롤러가 폰에 빙의할때 AI실행

 

NPC에 AI컨트롤러 적용


생성자

APPGASCharacterNonPlayer::APPGASCharacterNonPlayer()
{
//AI
	static ConstructorHelpers::FClassFinder<AController> AIControllerRef(TEXT("/Script/CoreUObject.Class'/Script/Project_P.PPAIController'"));
	if (AIControllerRef.Class)
	{
		AIControllerClass = AIControllerRef.Class;
	}
	
	AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}

 

  • ConstructorHelpers의 Finder함수로 생성한 AI컨트롤러를 가져옴
  • AIControllerClass = AIControllerRef.Class;
    • 부모클래스에 선언되어있는 AIControllerClass 변수에 가져온 AI컨트롤러를 대입
  • AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
    • AutoPossessAI 를 변경하여 AI를 언제 적용할지 설정