인공지능 - 행동트리 모델의 이해

Unreal 이론|2024. 11. 10. 15:32

[이득우의 언리얼 프로그래밍 Part2 수업의 정리]

 

행동 트리(Behavior Tree)의 역사

  • 2004년 개발사 번지의 헤일로2에서 인공지능을 설계하는데 사용됨
  • 2005년 GDC에서 발표 : "Handling Complexity in the Halo 2 AI"
  • 우선순위와 트리구조를 사용해 인공지능을 설계하는 기법
  • 단순한 행동에서 복잡한 행동으로 이어지도록 설계
  • 게임산업에서 개량해 널리 사용하고 있음

행동 트리 모델의 장점

  • FSM이 가지고 있던 문제를 해결하는 새로운 게임 인공지능 모델의 수립
  • 행동 트리 모델의 장점
    • 모듈화 잘 되어있어 확장 자유로움
    • 트리를 기반으로 계층화 잘 되어있어, 복잡한 인공지능 모델을 쉽게 설계할 수 있음
    • 다이어그램으로 인공지능 모델을 효과적으로 표현할 수 있음
    • 제공되는 여러 편리한 부가 기능을 활용해 다양한 상황에 대해 손쉽게 제어 가능

행동 트리 모델의 구성 요소

  • 트리에서 항상 왼쪽에 있는 노드에 우선 순위 부여
  • 시작 상태에서 설정할 필요 없이 왼쪽에서부터 깊이 우선 탐색(DFS)을 시작한다

Root에 의해 의사결정이 이루어진다

 

행동 트리 모델의 구성 요소

  • 행동을 중심으로 설계
  • 단, 부모 노드에서 다수의 행동을 컨트롤. 이를 컴포짓(Composite)이라 함
    • 셀렉터 (여러 행동 중 하나의 행동을 지정)
    • 시퀀스 (여러 행동을 모두 수행)
    • 패러렐 (여러 행동을 함께 수행)
  • ex) 밥먹기, 영화보기 두 행동이 있다면
    • 셀렉터: 밥과 영화 중 하나를 선택
    • 시퀀스: 밥을 먹은 후 영화를 봄
    • 패러렐: 밥을 먹으며 영화를 봄
  • 행동에 대한 다양한 결과
    • 성공 (Succeeded): 행동의 성공
    • 실패 (Failed): 행동의 실패
    • 중지 (Aborted): 외부 요인으로 인한 행동의 실패
    • 진행 중 (InProgress): 행동 결과를 홀딩
  • 컴포짓 노드마다 다른 행동 결과 처리
    • 셀렉터: 성공한 노드가 나오면 종료 (밥이 안나오면 대신 영화 시청)
    • 시퀀스: 실패한 노드가 나올때까지 진행 (밥을 안먹었다면 영화도 안봄)
  • 컴포짓 노드에 부착하는 다양한 추가 기능
    • 데코레이터(Decorator): 컴포짓 노드가 실행되는 조건 지정, 만족할때만 노드 실행
    • 서비스(Service): 컴포짓 노드가 활성화될 때 주기적으로 실행하는 부가 명령
    • 관찰자 중단(Abort): 데코레이터 조건에 부합되면 컴포짓 내 활동을 모두 중단

행동 트리 모델의 예시

  • 퇴근하고 집에 가는 행동 트리 모델의 설정
    • 지하철 역까지 이동 -> 지하철 탑승 -> 버스 환승 -> 문앞 도착
    • 시퀀스 컴포짓을 사용해 이들을 묶는다.

 

  • 트리가 가진 깊이를 활용해 단계별로 세부적인 행동 설계
  • 퇴근하고 집에가기 
    • 1단계: 지하철 역까지 이동한 후, 지하철 탑승, 버스환승, 문앞 도착
    • 2단계: 셀렉터 컴포짓을 사용해 지하철 역까지 걷거나 버스를 타거나 둘 중 하나 선택

 

컴포짓의 데코레이터 설정

  • 컴포짓에 조건을 걸어 선택의 폭 넓힐 수 있도록 확장
  • 우선 순위가 높은 컴포짓을 왼쪽에 배치, 데코레이터 설정

 

컴포짓에 관찰자 중단(Abort) 설정

  • 비상상황에 대한 처리. ex) 친구로부터 함께 놀자는 연락 왔다.
  • 트리 맨 왼쪽에 친구에게 간다는 컴포짓 추가
  • 집에 가는 모든 컴포짓에 친구와 약속이라는 Abort 추가
  • 친구에게 연락이 오면 집에 가던 모든 행동 중단 후 Root에서 다시 판단

행동 트리 모델의 구현 예시

  • 전형적인 RPG 게임 NPC에 대한 행동 트리 모델 예시
  • 쉬기(IDLE)와 정찰(PATROL)에 상태에 대한 행동 트리

  • 전형적인 RPG 게임 플레이어에 대한 행동 트리 모델 예시
  • 추가적으로 추격(CHASE)과 공격(ATTACK) 상태에 대한 행동 트리

 

그렇다면 실제 적용은 어떻게 하는가?

  • 월드에 배치된 캐릭터, SpawnActor 함수를 사용해 스폰시킨 캐릭터 둘 중 어느쪽에 AI를 적용할지 선택하는 Auto Possess AI 옵션. 둘다 적용하도록 선택
  • NPC 액터에 빙의할 AI 컨트롤러 클래스 선택하는 옵션 - 행동 트리 모델 적용한 클래스 새로 생성
// ABCharacterNonPlayer.cpp

#include "AI/ABAIController.h"

AABCharacterNonPlayer::AABCharacterNonPlayer()
{
	GetMesh()->SetHiddenInGame(true);

	AIControllerClass = AABAIController::StaticClass();
	AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}
  • NPC 생성자 코드에 AIControllerClass 할당

Behavior Tree, Blackboard 두가지 에셋을 추가

  • Blackboard: 인공지능 모델에서 의사결정을 하기 위한 기본 데이터 제공하는 데이터 저장소
// ABAIController.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

/**
 * 
 */
UCLASS()
class ARENABATTLE_API AABAIController : public AAIController
{
	GENERATED_BODY()

public:
	AABAIController();

	void RunAI();
	void StopAI();

protected:
	// 어떤 컨트롤러가 폰에 빙의해서 조종할때 발생되는 이벤트 함수
	virtual void OnPossess(APawn* InPawn) override;
	
private:
	UPROPERTY()
	TObjectPtr<class UBlackboardData> BBAsset;

	UPROPERTY()
	TObjectPtr<class UBehaviorTree> BTAsset;

};

// ABAIController.cpp
// Fill out your copyright notice in the Description page of Project Settings.


#include "AI/ABAIController.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BlackboardData.h"
#include "BehaviorTree/BlackboardComponent.h"

AABAIController::AABAIController()
{
	static ConstructorHelpers::FObjectFinder<UBlackboardData> BBAssetRef(TEXT("/Script/AIModule.BlackboardData'/Game/ArenaBattle/AI/BB_ABCharacter.BB_ABCharacter'"));
	if (nullptr != BBAssetRef.Object)
	{
		BBAsset = BBAssetRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UBehaviorTree> BTAssetRef(TEXT("/Script/AIModule.BehaviorTree'/Game/ArenaBattle/AI/BT_ABCharacter.BT_ABCharacter'"));
	if (nullptr != BTAssetRef.Object)
	{
		BTAsset = BTAssetRef.Object;
	}
}

void AABAIController::RunAI()
{
	UBlackboardComponent* BlackboardPtr = Blackboard.Get();
	if (UseBlackboard(BBAsset, BlackboardPtr)) {
		bool RunResult = RunBehaviorTree(BTAsset);
		ensure(RunResult);
	}
}

void AABAIController::StopAI()
{
	UBehaviorTreeComponent* BTComponent = Cast<UBehaviorTreeComponent>(BrainComponent);
	if (BTComponent) {
		BTComponent->StopTree();
	}
}

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

	RunAI();
}
  • 이후 ABAIController에서 Blackboard, BehaviorTree 에셋을 가져오고, 간단히 동작+정지 함수 구현

'Unreal 이론' 카테고리의 다른 글

헤드업디스플레이의 구현  (0) 2024.11.14
인공지능 - 행동트리 모델의 구현  (0) 2024.11.11
게임데이터 관리  (0) 2024.11.06
무한 맵의 제작  (0) 2024.10.31
아이템 시스템  (1) 2024.10.30

댓글()