AI_Perception(플레이어 감지)

2025. 4. 23. 21:09·내배캠/Unreal Engine

📌 AI Perception Component

언리얼 엔진에서 AI가 감지할 수 있게 해주는 센서 시스템이다.
시각, 청각, 데미지 등 다양한 자극(Stimulus)을 감지하고, 그 정보를 AIController에 전달해서 AI의 의사결정에 활용된다.
간단하게 AI에게 시각을 부여해서 특정 거리안에 있으면 AI가 시각적으로 플레이어를 인식하고, 범위를 벗어나면 시각적으로 인지하지 못해 더 이상 추격이 불가능한 상태를 구현해보려한다.

 

✅ AIController 구현

*AIController.h

더보기
#pragma once

#include "CoreMinimal.h"
#include "AIController.h"
#include "Perception/AIPerceptionComponent.h"
#include "Perception/AISenseConfig_Sight.h"
#include "Chaser_AIController.generated.h"

UENUM(BlueprintType)
enum class EAIState : uint8
{
	Idle,
	Suspicious,
	chasing
};

UCLASS()
class AI_TEST_API AChaser_AIController : public AAIController
{
	GENERATED_BODY()
	
public:
	AChaser_AIController();

	UFUNCTION(BlueprintCallable, Category = "AI")
	void StartChasing(AActor* Target);
	UFUNCTION(BlueprintCallable, Category = "AI")
	void StopChasing();

	UFUNCTION(BlueprintCallable, Category = "AI")
	EAIState GetCurrentState() const { return CurrentState; }

protected:
	virtual void Tick(float DeltaTime) override;

	UFUNCTION()
	void OnperceptionUpdated(AActor* Actor, FAIStimulus Stimulus);

	UFUNCTION(BlueprintCallable, Category = "AI")
	void UpdateAIState();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
	float DetectionRadius;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
	float LoseInterestRadius;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
	float chaseRadius;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AI")
	UAIPerceptionComponent* AIPerceptionComponent;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AI")
	UAISenseConfig_Sight* SightConfig;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
	AActor* TargetActor;

private:
	bool bIsChasing;

	EAIState CurrentState;

	FVector LastKnownLocation;
};

*AIController.cpp

더보기
#include "Chaser_AIController.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/Character.h"
#include "DrawDebugHelpers.h"

AChaser_AIController::AChaser_AIController()
{
	PrimaryActorTick.bCanEverTick = true;

	DetectionRadius = 1000.0f;
	LoseInterestRadius = 1500.0f;
	chaseRadius = 800.0f;

	LastKnownLocation = FVector::ZeroVector;

	bIsChasing = false;

	CurrentState = EAIState::Idle;

	TargetActor = nullptr;

	SightConfig = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("SightConfig"));
	SightConfig->SightRadius = DetectionRadius;
	SightConfig->LoseSightRadius = LoseInterestRadius;
	SightConfig->PeripheralVisionAngleDegrees = 90.0f;
	SightConfig->DetectionByAffiliation.bDetectEnemies = true;
	SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
	SightConfig->DetectionByAffiliation.bDetectFriendlies = true;

	PerceptionComponent = CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("PerceptionComponent"));
	SetPerceptionComponent(*PerceptionComponent);

	PerceptionComponent->ConfigureSense(*SightConfig);
	PerceptionComponent->SetDominantSense(*SightConfig->GetSenseImplementation());
	PerceptionComponent->RequestStimuliListenerUpdate();
	PerceptionComponent->OnTargetPerceptionUpdated.AddDynamic(this, &AChaser_AIController::OnperceptionUpdated);
}

void AChaser_AIController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	UpdateAIState();

	if (bIsChasing && TargetActor)
	{
		APawn* ControlledPawn = GetPawn();
		if (ControlledPawn)
		{
			float Distance = FVector::Dist(ControlledPawn->GetActorLocation(), TargetActor->GetActorLocation());

			if (Distance <= chaseRadius)
			{
				MoveToActor(TargetActor, 100.0f);

				LastKnownLocation = TargetActor->GetActorLocation();

#if WITH_EDITOR
				DrawDebugLine(
					GetWorld(),
					ControlledPawn->GetActorLocation(),
					TargetActor->GetActorLocation(),
					FColor::Red,
					false,
					-1.0f,
					0,
					2.0f
				);
#endif
			}
			else if (Distance > LoseInterestRadius)
			{
				StopChasing();
			}
		}
	}
}

void AChaser_AIController::StartChasing(AActor* Target)
{
	TargetActor = Target;
	bIsChasing = true;

	if (Target)
	{
		LastKnownLocation = Target->GetActorLocation();
	}

	CurrentState = EAIState::chasing;
}

void AChaser_AIController::StopChasing()
{
	bIsChasing = false;
	TargetActor = nullptr;

	StopMovement();

	CurrentState = EAIState::Idle;
}

void AChaser_AIController::OnperceptionUpdated(AActor* Actor, FAIStimulus Stimulus)
{
	ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
	UE_LOG(LogTemp, Warning, TEXT("Perception on"));
	if (Actor == PlayerCharacter)
	{
		if (Stimulus.Type == UAISense::GetSenseID<UAISense_Sight>())
		{
			TargetActor = Actor;

			APawn* ControlledPawn = GetPawn();
			if (ControlledPawn)
			{
				float Distance = FVector::Dist(ControlledPawn->GetActorLocation(), Actor->GetActorLocation());

				if (Distance <= chaseRadius)
				{
					StartChasing(Actor);
				}
				else if (Distance <= DetectionRadius)
				{
					CurrentState = EAIState::Suspicious;
				}
			}
		}

		else
		{
			if (CurrentState == EAIState::chasing)
			{
				MoveToLocation(LastKnownLocation, 50.0f);

				CurrentState = EAIState::Suspicious;
			}
		}
	}
}

void AChaser_AIController::UpdateAIState()
{
	if (!TargetActor) return;

	APawn* ControlledPawn = GetPawn();
	if (!ControlledPawn) return;

	float DistanceToTarget = FVector::Dist(ControlledPawn->GetActorLocation(), TargetActor->GetActorLocation());

	switch(CurrentState)
	{
	case EAIState::Idle:
		if (DistanceToTarget <= DetectionRadius)
		{
			CurrentState = EAIState::Suspicious;
		}
		break;

	case EAIState::Suspicious:
		if (DistanceToTarget <= chaseRadius)
		{
			StartChasing(TargetActor);
		}
		else if (DistanceToTarget > DetectionRadius)
		{
			CurrentState = EAIState::Idle;
		}
		break;

	case EAIState::chasing:
		if (DistanceToTarget > LoseInterestRadius)
		{
			StopChasing();
		}
		break;
	}
}

🔔 테스트 결과

시각적으로 AI가 인지해서 쫓아오다가 일정 거리 멀어지게되면 플레이어의 정보를 잃고 제자리에 멈춘 것을 확인할 수 있었다.

'내배캠 > Unreal Engine' 카테고리의 다른 글

Debug Helper 만들기  (0) 2025.05.01
AI_NavLink  (0) 2025.04.23
AI_RVO(회피 이동)  (0) 2025.04.23
AI_NavMesh  (0) 2025.04.22
미로 게임 구현(Dedicated Server)  (0) 2025.03.25
'내배캠/Unreal Engine' 카테고리의 다른 글
  • Debug Helper 만들기
  • AI_NavLink
  • AI_RVO(회피 이동)
  • AI_NavMesh
동그래님
동그래님
  • 동그래님
    개발자 동그래
    동그래님
  • 전체
    오늘
    어제
    • 분류 전체보기 (210)
      • 공부 (51)
        • Code Cata (50)
      • 내배캠 (151)
        • TIL (50)
        • C++ (37)
        • Unreal Engine (48)
        • GAS(Gameplay Ability System.. (16)
      • Project (7)
        • Gunfire Paragon (5)
        • Arena Fighters (1)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.3
    동그래님
    AI_Perception(플레이어 감지)
    상단으로

    티스토리툴바