EDR_Project / AIController

EDR_Project의 EnemyCharacter에 사용될 AIController 소스입니다.

 

 

Enemy_EDR_AIController.h

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

#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "Perception/AIPerceptionTypes.h"
#include "Enemy_EDR_AIController.generated.h"

/**
 * 
 */
UCLASS()
class EDR_API AEnemy_EDR_AIController : public AAIController
{
	GENERATED_BODY()

public:
	AEnemy_EDR_AIController(FObjectInitializer const& object_initializer);
	void BeginPlay() override;
	void OnPossess(APawn* pawn) override;

	class UBlackboardComponent* get_blackboard() const;

private:
	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "AI", meta = (AllowPrivateAccess = "true"))
	class UBehaviorTreeComponent* behavior_tree_component;

	UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = "AI", meta = (AllowPrivateAccess = "true"))
	class UBehaviorTree* btree;

	class UBlackboardComponent* blackboard;
	class UAISenseConfig_Sight* SightConfig;


	// 타이머 핸들러
	FTimerHandle TimerHandle;

	// 비동기 로딩을 위한 콜백 함수
	void OnBehaviorTreeLoaded();

	// 비헤이비어 트리 로드 재시도 함수
	void RetryLoadBehaviorTree();
public:
	static const FName HomePosKey;
	static const FName TargetLocation;
	static const FName TargetKey;

	UFUNCTION()
	void OnUpdated(TArray<AActor*> const& updated_actors);
	UFUNCTION()
	void OnTargetDetected(AActor* actor, FAIStimulus const Stimulus);
	UFUNCTION()
	void SetPerceptionSystem();

	//AI Perception 변수
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AISightRadius = 500.f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AILoseSightRadius = 50.f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AIFieldOfView = 90.f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AISightAge = 5.f;
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float AILastSeenLocation = 900.f;

};

 

반응형

 

Enemy_EDR_AIContoller.cpp

 

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

#include "Enemy_EDR_AIController.h"
#include "UObject/ConstructorHelpers.h"
#include "BehaviorTree/BehaviorTree.h"
#include "BehaviorTree/BehaviorTreeComponent.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Perception/AISenseConfig_Sight.h"
#include "Perception/AIPerceptionStimuliSourceComponent.h"
#include "Perception/AIPerceptionComponent.h"
#include "BlackBoardKeys.h"
#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "EngineGlobals.h"
#include "MyCharacter.h"

const FName AEnemy_EDR_AIController::HomePosKey(TEXT("HomePos"));
const FName AEnemy_EDR_AIController::TargetLocation(TEXT("TargetLocation"));
const FName AEnemy_EDR_AIController::TargetKey(TEXT("Target"));

AEnemy_EDR_AIController::AEnemy_EDR_AIController(FObjectInitializer const& object_initializer)
{
	//ConstructorHelpers로 에디터에 미리 만들어둔 비헤이비어트리를 지정
	static ConstructorHelpers::FObjectFinder<UBehaviorTree>BTObject(TEXT("BehaviorTree'/Game/GJ/AI/EneMy_Ai/Enemy_EDR_BehaviorTree.Enemy_EDR_BehaviorTree'"));
	if (BTObject.Succeeded())
	{
		btree = BTObject.Object;
	}
	else
	{
	}
	behavior_tree_component = object_initializer.CreateDefaultSubobject<UBehaviorTreeComponent>(this, TEXT("BehaviorComp"));
	blackboard = object_initializer.CreateDefaultSubobject<UBlackboardComponent>(this, TEXT("BlackboardComp"));

	//Perception초기화
	SetPerceptionSystem();


}
void AEnemy_EDR_AIController::BeginPlay()
{
    Super::BeginPlay();

    if (!IsValid(btree))
    {
        // 트리가 유효하지 않을 경우 재시도
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Behavior Tree is not valid, retrying..."));
        GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AEnemy_EDR_AIController::RetryLoadBehaviorTree, 1.0f, true);
    }
    else
    {
        // 유효하면 실행
        RunBehaviorTree(btree);
        behavior_tree_component->StartTree(*btree);
    }
}

void AEnemy_EDR_AIController::RetryLoadBehaviorTree()
{
    if (IsValid(btree))
    {
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("Behavior Tree loaded successfully!"));
        GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
        
        RunBehaviorTree(btree);
        behavior_tree_component->StartTree(*btree);
    }
}
void AEnemy_EDR_AIController::OnPossess(APawn* pawn)
{
	Super::OnPossess(pawn);

	if (!pawn)
	{
		UE_LOG(LogTemp, Warning, TEXT("Pawn is null in OnPossess."));
		return;
	}

	if (!blackboard || !btree)
	{
		UE_LOG(LogTemp, Warning, TEXT("Blackboard or Behavior Tree is null in OnPossess."));
		return;
	}

	// 비헤이비어 트리와 블랙보드 초기화
	blackboard->InitializeBlackboard(*btree->BlackboardAsset);
	behavior_tree_component->StartTree(*btree);

	UE_LOG(LogTemp, Log, TEXT("AI Controller has possessed the pawn and initialized behavior tree and blackboard."));
}
UBlackboardComponent* AEnemy_EDR_AIController::get_blackboard() const
{
	return blackboard;
}

void AEnemy_EDR_AIController::OnUpdated(TArray<AActor*> const& updated_actors)
{
}
void AEnemy_EDR_AIController::OnTargetDetected(AActor* actor, FAIStimulus const Stimulus)
{
	if (auto const player = Cast<AMyCharacter>(actor))
	{
		// 플레이어가 감지되면 블랙보드에 정보를 설정
		get_blackboard()->SetValueAsBool(bb_keys::can_see_player, Stimulus.WasSuccessfullySensed());

		// 플레이어 위치를 블랙보드에 저장
		if (Stimulus.WasSuccessfullySensed())
		{
			get_blackboard()->SetValueAsVector(bb_keys::target_location, player->GetActorLocation());
			UE_LOG(LogTemp, Log, TEXT("Player detected, updating blackboard target location."));
		}
	}
}
// Ai Perception
void AEnemy_EDR_AIController::SetPerceptionSystem()
{
	SightConfig = CreateOptionalDefaultSubobject<UAISenseConfig_Sight>(TEXT("Sight Config"));
	SetPerceptionComponent(*CreateOptionalDefaultSubobject<UAIPerceptionComponent>(TEXT("AI Perception")));


	SightConfig->SightRadius = AISightRadius;
	SightConfig->LoseSightRadius = SightConfig->SightRadius + AILoseSightRadius;
	SightConfig->PeripheralVisionAngleDegrees = AIFieldOfView;
	SightConfig->SetMaxAge(AISightAge);
	SightConfig->AutoSuccessRangeFromLastSeenLocation = AILastSeenLocation;

	SightConfig->DetectionByAffiliation.bDetectEnemies = true;
	SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
	SightConfig->DetectionByAffiliation.bDetectFriendlies = true;

	GetPerceptionComponent()->SetDominantSense(*SightConfig->GetSenseImplementation());
	GetPerceptionComponent()->OnTargetPerceptionUpdated.AddDynamic(this, &AEnemy_EDR_AIController::OnTargetDetected);
	GetPerceptionComponent()->ConfigureSense(*SightConfig);
}

 

 

블루프린트로 제작했었던 AIController를 언리얼 c++로 옮겨보았습니다.

 

 

AIContoroller 적용한 모습입니다.

'Unreal Engine 5 > EDR_Project' 카테고리의 다른 글

EDR_Project / CanAttack  (0) 2024.10.17
EDR_Project / Detect  (0) 2024.10.17
EDR_Project / Patrol  (0) 2024.10.17
EDR_Project / BehaviorTree, BlackBoard  (0) 2024.10.17
EDR_Project / Character  (0) 2024.10.17