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 |