How to use AIPerceptionComponent and multiple Sense config (AIPerceptionTypes C++)

Hi!
I want to use the AIPerceptionComponent with multiple AISenseConfig. I want to be able to make different actions depending on which sense is triggered.

For now I’m able to trigger Damage and hearing events but the sight dont work. It works with the same code alone in his own AIPerceptionComponent but not with two others.

Is it a good practice to have multiple AIPerceptionComponent on the same Controller to separate sense?

At same time, I was wondering what it is the best practice to differentiate between the senses

    #include "CivilianAIController.h"
    #include "Kismet/GameplayStatics.h"
    #include "BehaviorTree/BlackboardComponent.h"
    #include "CivilianCharacter.h"
    #include  "Perception/AIPerceptionComponent.h"
    #include "Perception/AISenseConfig_Sight.h"
    #include "Perception/AISenseConfig_Hearing.h"
    #include "Perception/AISenseConfig_Damage.h"
    
    ACivilianAIController::ACivilianAIController(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {
    	PerceptionComponent = CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("AIHearing Component"));		
    
    	SightConfig = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("Sight Config"));
    	HearingConfig = CreateDefaultSubobject<UAISenseConfig_Hearing>(TEXT("Hearing Config"));	
    	DamageConfig = CreateDefaultSubobject<UAISenseConfig_Damage>(TEXT("Damage Config"));
    
    	PerceptionComponent->ConfigureSense(*SightConfig);
    	PerceptionComponent->ConfigureSense(*HearingConfig);
    	PerceptionComponent->ConfigureSense(*DamageConfig);
    	
    	PerceptionComponent->SetDominantSense(SightConfig->GetSenseImplementation());
    
    	PerceptionComponent->OnTargetPerceptionUpdated.AddDynamic(this, &ACivilianAIController::TargetPerceptionUpdated);
    }
    
    void ACivilianAIController::OnPossess(APawn* InPawn)
    {
    	Super::OnPossess(InPawn);
    
    	if (SightConfig && PerceptionComponent)
    	{
    		SightConfig->SightRadius = SightRadius;
    		SightConfig->LoseSightRadius = LoseSightRadius;
    		SightConfig->PeripheralVisionAngleDegrees = PeripheralVisionDegrees;
    		SightConfig->DetectionByAffiliation.bDetectEnemies = true;
    		SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
    		SightConfig->DetectionByAffiliation.bDetectFriendlies = true;
    		PerceptionComponent->ConfigureSense(*SightConfig);
    	}	
    
    	if (HearingConfig && PerceptionComponent)
    	{
    		HearingConfig->HearingRange = AIHearingRange;
    		HearingConfig->DetectionByAffiliation.bDetectEnemies = true;
    		HearingConfig->DetectionByAffiliation.bDetectNeutrals = true;
    		HearingConfig->DetectionByAffiliation.bDetectFriendlies = true;
    		PerceptionComponent->ConfigureSense(*HearingConfig);
    	}
    }
    
    void ACivilianAIController::BeginPlay()
    {
    	Super::BeginPlay();
    
    	if (AIBehavior)
    	{
    		PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
    		RunBehaviorTree(AIBehavior);
    		GetBlackboardComponent()->SetValueAsVector(TEXT("StartLocation"), GetPawn()->GetActorLocation());
    	}
    }
    
    void ACivilianAIController::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    } 
    
    void ACivilianAIController::TargetPerceptionUpdated(AActor* Actor, FAIStimulus Stimulus)
    {        	
    	UAISenseConfig* SenseUpdated = PerceptionComponent->GetSenseConfig(Stimulus.Type);
    	if (SenseUpdated)
    	{
    		if (SenseUpdated->GetClass() == HearingConfig->GetClass())
    		{
    			UE_LOG(LogTemp, Warning, TEXT("Pawn hearded in PerceptionUpdated"));
    		}
    		else if (SenseUpdated->GetClass() == SightConfig->GetClass())
    		{
    			UE_LOG(LogTemp, Warning, TEXT("Pawn saw in PerceptionUpdated"));
    		}
    		else if (SenseUpdated->GetClass() == DamageConfig->GetClass())
    		{
    			UE_LOG(LogTemp, Warning, TEXT("Pawn damaged in PerceptionUpdated"));
    		}
    	}
}

Header:

#pragma once

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


/**
 * 
 */

UCLASS()
class SAMPLESHOOTERREMIX_API ACivilianAIController : public AAIController
{
	GENERATED_BODY()
public:

	ACivilianAIController(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());	

	virtual void Tick(float DeltaTime) override;

	bool IsDead() const;
	
	UFUNCTION()
	void TargetPerceptionUpdated(AActor* Actor, FAIStimulus Stimulus);

protected:

	virtual void OnPossess(APawn* InPawn) override;

	virtual void BeginPlay() override;

	class UAIPerceptionComponent* PerceptionComponent;

	//class UAIPerceptionComponent* SightPerceptionComponent;

	class UAISenseConfig_Sight* SightConfig;

	class UAISenseConfig_Hearing* HearingConfig;

	class UAISenseConfig_Damage* DamageConfig;

private:

	UPROPERTY(EditAnywhere)
	class UBehaviorTree* AIBehavior;

	APawn* PlayerPawn;

	UPROPERTY(EditDefaultsOnly)
	float SightRadius;

	UPROPERTY(EditDefaultsOnly)
	float LoseSightRadius;

	UPROPERTY(EditDefaultsOnly)
	float PeripheralVisionDegrees;


	UPROPERTY(EditDefaultsOnly)
	float AIHearingRange;
};
1 Like

I think you will have an easier time setting the properties of the senses and the perception component in blueprints.

You should not be creating multiple perception components for each sense.

The AIPerceptionComponent has an event:
image

Which passes out the Stimulus that the perception updated event was caused by:

Which has the type of sense that caused the stimulus:
image

It isn’t a UPROPERTY however, so you might only be able to access that information in C++

1 Like