유니티의 경우 AI를 제어하려면 AIController같은 클래스를 만들어서 컴포넌트로 붙여서 제어하게 되는데 언리얼도 유사하게 되어있다.

언리얼은 이미 구조가 어느정도 잡혀있다는점이 조금 다르다.

AIController는 AI에 빙의 되었다가 풀렸다 하면서 제어가 된다.

 

AIController를 상속받는 클래스를 하나 만들어주도록 하자.

 

언리얼에서는 Behavior Tree라는것을 제공해주는데 항상 사용해야 되는것은 아니고 매우 간단한 AI같은 경우는 상태기계를 이용하는게 더 쉬울 수 있다.

Behavior Tree는 보통 서버쪽에서 만들어진다.

 

우선 모듈을 추가로 사용해야 하기 때문에 cs파일에 모듈을 추가해주자.

 

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "NavigationSystem", "AIModule", "GameplayTasks" });

 

NavigationSytstem은 단어 그대로 내비게이션 시스템을 사용하기 위해 필요하고 AIModule은 AIController를 사용하기 위해서 필요하다. GameplayTasks는 이번시간은 아니지만 차후 Behavior Tree를 사용할 때 필요하므로 미리 넣어준다.

 

 

// MyAIController.h
UCLASS()
class TESTUNREALENGINE_API AMyAIController : public AAIController
{
    GENERATED_BODY()

public:
    AMyAIController();

    virtual void OnPossess(APawn* InPawn) override;
    virtual void OnUnPossess() override;

private:
    void RandomMove();

private:
    // 타이머 매니저에 콜백을 등록하기 위해 필요한 핸들
    FTimerHandle TimerHandle;
};

// MyAIController.cpp
#include "NavigationSystem.h"
#include "Blueprint/AIBlueprintHelperLibrary.h"

AMyAIController::AMyAIController()
{
}

void AMyAIController::OnPossess(APawn* InPawn)
{
    // 빙의 시
    Super::OnPossess(InPawn);

    // 월드의 타이머 매니저에 콜백을 등록한다
    GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMyAIController::RandomMove, 3.f, true);
}

void AMyAIController::OnUnPossess()
{
    // 빙의 해제 시
    Super::OnUnPossess();

    // 등록된 콜백을 해제한다
    GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
}

void AMyAIController::RandomMove()
{
    auto CurrentPawn = GetPawn();

    // 월드의 내비게이션 시스템을 가져온다
    UNavigationSystemV1* NavSystem = UNavigationSystemV1::GetNavigationSystem(GetWorld());

    if (NavSystem == nullptr)
        return;

    FNavLocation RandomLocation;

    // 월드의 내비게이션 범위중 원점(첫번째 매개변수)을 기준으로 반지름 만큼의 범위를 한정지어
    // 랜덤한 좌표를 가져온다(RandomLocation에 저장됨)
    if (NavSystem->GetRandomPointInNavigableRadius(FVector::ZeroVector, 500.f, RandomLocation))
    {
        UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, RandomLocation);
    }
}

 

OnPossess와 OnUnPossess는 빙의 시, 빙의 해제 시 실행되는 함수이다. OnOverlapBegin/End같은 트리거 이벤트라고 보면 될 듯 하다.

 

빙의시 타이머 매니저에 의해 콜백이 등록되고 해제되는데 이와 같은 패턴이 서버를 만들때도 비슷하게 만들어진다.

 

 

AMyCharacter::AMyCharacter()
{
    AIControllerClass = AMyAIController::StaticClass();
    AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
}

 

AIControllerClass는 Pawn에 기본적으로 생성되어있는 AIController이다. 이것을 방금 만든 AIController로 바꿔준다.

AutoPossessAI는 자동 빙의 규칙인데 기본적으로 플레이어가 빙의된 경우는 무시된다.

월드에 배치되거나 스폰된 경우 AIController가 자동으로 빙의되도록 한다.

 

월드에 내비 메시 바운드 볼륨을 깔고 실행하면 플레이어가 아닌 맵에 배치된 캐릭터가 3초마다 랜덤한 곳으로 이동한다.

 

[정리]

 

  • AIController는 AI에 빙의와 해제를 반복하여 AI를 제어한다.
  • 비헤이비어 트리가 강력한 툴인것은 맞지만 구현이 복잡하기 때문에 매우 간단한 AI로직의 경우 꼭 비헤이비어 트리를 사용할 필요는 없다.

'언리얼 엔진 > 언리얼 엔진4 입문' 카테고리의 다른 글

[UE4 입문] Behavior Tree #2  (0) 2022.09.12
[UE4 입문] Behavior Tree #1  (0) 2022.09.12
[UE4 입문] UI 실습  (0) 2022.09.03
[UE4 입문] 스탯 매니저  (0) 2022.09.02
[UE4 입문] 아이템 줍기  (0) 2022.09.02

+ Recent posts