포트폴리오 제작/Project_P

Project_P AI Perception Damage Sense 적용

k99812 2025. 5. 30. 16:46

Damage Sense

기존 몬스터 AI는 몬스터 뒤로 몰래 다가가 때려도 바보처럼 맞기만 했다.

그래서 AI Perception에서 제공하는 Damage Sense를 활용하여 몬스터가 공격당하면
플레이어를 감지할 수 있도록구현 해보았다.

 

Damage Sense 생성

APPAIController 헤더파일

virtual void PerceptionSensedDamage(APawn* Pawn_);

UPROPERTY(VisibleAnywhere)
TObjectPtr<class UAISenseConfig_Damage> SenseConfig_Damage;

 

  • virtual void PerceptionSensedDamage(APawn* Pawn_);
    • ActorPerceptionUpdated 함수에 들어온 FAIStimulus이 Dmage일경우
      실행할 함수
  • TObjectPtr<class UAISenseConfig_Damage> SenseConfig_Damage;
    • 데미지 센스를 저장할 변수

 

APPAIController Cpp파일

생성자

SenseConfig_Damage = CreateDefaultSubobject<UAISenseConfig_Damage>(TEXT("SenseConfig_Damage"));

SenseConfig_Damage->SetMaxAge(GruntAIData->AISenseAge);
AIPerceptionComp->ConfigureSense(*SenseConfig_Damage);

 

  • SenseConfig_Damage = CreateDefaultSubobject<UAISenseConfig_Damage>(TEXT("SenseConfig_Damage"));
    • 데미지 센스 생성
  • SenseConfig_Damage->SetMaxAge(GruntAIData->AISenseAge);
    • 데미지 센스 정보의 유효시간 설정
  • AIPerceptionComp->ConfigureSense(*SenseConfig_Damage);
    • AIPerceptionComp에 생성한 데미지 센스를 등록

 

ActorPerceptionUpdated

void APPAIController::ActorPerceptionUpdated(AActor* Actor, FAIStimulus Stimulus)
{
	APawn* PerceptionedPawn = Cast<APawn>(Actor);

	if (PerceptionedPawn && PerceptionedPawn->GetController()->IsPlayerController())
	{
		TSubclassOf<UAISense> SensedStimulsClass = UAIPerceptionSystem::GetSenseClassForStimulus(this, Stimulus);

		~~~

		if (SensedStimulsClass == UAISense_Damage::StaticClass())
		{
			PerceptionSensedDamage(PerceptionedPawn);
		}
	}
}

 

  • if (SensedStimulsClass == UAISense_Damage::StaticClass())
    {
               PerceptionSensedDamage(PerceptionedPawn);
    }
    • Stimulus가 Damage이면 PerceptionSensedDamage함수 실행하여 감지된 액터를 넘겨줌

 

PerceptionSensedDamage

void APPAIController::PerceptionSensedDamage(APawn* PerceptionedPawn)
{
	UE_LOG(LogTemp, Log, TEXT("Perception Sensed by Damage : %s"), *PerceptionedPawn->GetName())

	if (IsValid(PerceptionedPawn))
	{
		GetBlackboardComponent()->SetValueAsObject(BBKEY_TARGET, PerceptionedPawn);
		AActor::SetActorTickEnabled(true);
		FindTargetDelegate.ExecuteIfBound(true);
	}
}

 

  • GetBlackboardComponent()->SetValueAsObject(BBKEY_TARGET, PerceptionedPawn);
    • 블랙보드의 Target을 감지된 액터로 지정

 

데미지 이벤트 발생

class UAISense_Damage : public UAISense
{
      static AIMODULE_API void ReportDamageEvent(~~~);
}

 

데미지 이벤트를 발생시키려면 UAISense_Damage 클래스에 있는  static 함수 ReportDamageEvent함수를 호출해야 된다

해당 함수에선 매개변수로 타격받은 액터, 가해 액터가 필요해 이 둘을 쉽게 얻을 수 있는 AttackHitCheck GA에서 호출을 하였다

 

UPPGA_AttackHitCheck Cpp

TraceResultCallback

void UPPGA_AttackHitCheck::TraceResultCallback(const FGameplayAbilityTargetDataHandle& DataHandle)
{
	//#include "AbilitySystemBlueprintLibrary.h" 추가
	if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(DataHandle, 0))
	{
		FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(DataHandle, 0);

		UAbilitySystemComponent* OwnerASC = GetAbilitySystemComponentFromActorInfo_Checked();
		UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitResult.GetActor());

		~~~
        
		//타겟이 몬스터일 경우 AI 데미지 센스 발동
		IGameplayTagAssetInterface* TargetActor = Cast<IGameplayTagAssetInterface>(HitResult.GetActor());
		if (TargetActor && TargetActor->HasMatchingGameplayTag(PPTAG_CHARACTER_MONSTER))
		{
			UAISense_Damage::ReportDamageEvent(this, HitResult.GetActor(), OwnerASC->GetAvatarActor(),
				OwnerAttributeSet->GetAttackRate(), HitResult.GetActor()->GetActorLocation(), HitResult.Location);
		}
	}
    
    ~~~
    
}

 

 

이 프로젝트에선 몬스터에 GameplayTag를 생성해 몬스터인지 캐릭터인지 태그를 부착했다.

언리얼 엔진에선 GAS 객체가 아니여도 GameplayTag를 손쉽게 사용할 수 있도록 IGameplayTagAssetInterface를 제공한다

 

  • IGameplayTagAssetInterface* TargetActor = Cast<IGameplayTagAssetInterface>(HitResult.GetActor());
    • IGameplayTagAssetInterface로 캐스팅
  • if (TargetActor && TargetActor->HasMatchingGameplayTag(PPTAG_CHARACTER_MONSTER))
    • 캐스팅이 성공 하고
    • 타겟액터에 몬스터 태그가 부착되어 있으면
    • PPTAG_CHARACTER_MONSTER
      FGameplayTag::RequestGameplayTag(FName("Character.Monster"))
  • UAISense_Damage::ReportDamageEvent(this, HitResult.GetActor(), OwnerASC->GetAvatarActor(),
    OwnerAttributeSet->GetAttackRate(), HitResult.GetActor()->GetActorLocation(), HitResult.Location);
    • UAISense_Damage::ReportDamageEvent를 호출해 데미지 이벤트를 발생시킨다

 

적용 영상