Where Should AI Perception Components be Attached?


I’ve been tracing through the code for the AI Controller and it would appear to expect the AI Perception Components to be attached to the controller rather than the Pawn (where I’ve been attaching them). Is this the preferred approach?

Specifically, AAIController::PostRegisterAllComponents() searches for a UAIPerceptionComponent, and won’t find it unless it’s on the Controller.

However, my stuff has been working (to date), mostly as a result of calls to AAIController::SetPerceptionComponent(…).

I merely checking that I’ve got the right end of the stick here, as I don’t recall any documentation for the AI Perception stuff suggesting that you needed to attach them to the Controller not the Pawn.

Many thanks!

Edit: Actually, the question is not very clear - the AI Perception component may need to be attached to a different part of the Pawn (the Controller?) to where the AI Perception Stimuli Source component is attached (the Pawn?). Clarification of this would be appreciated.


Hey Stuart,

AIController’s perception component lookup in PostRegisterAllComponents is just a convenience for people adding AIPerceptionComponentto their controllers. It makes it “just work”. But you can have your component wherever you want, so using SetPerceptionComponent route is good as well, either way is fine.



Edit: noticed the edit :smiley: By design AIPerceptionStimuliSourceComponent is totally optional for the while AIPerceptionSystem so it doesn’t matter where it is in relation to AIPerceptionComponent.

As a kicker to this, I’ve just found out that the “Player” doesn’t have an AI Controller (even though the Pawn defines one). And the APlayerController doesn’t have an interface to the AIPerceptionComponent. Which rather boils what I was hoping to achieve here…

I’ll explain - I was hoping to use the Perception stuff on top of the player to feed into logic that could be used to describe what the player can see/hear/etc. E.g. knowing whether the player could see a particular actor (or how long it had been since the actor was seen), whether they heard a particular sound effect go off, etc.

Without an AI Controller on the player, I guess I don’t have any of this data available? Any clues as to how I’d go about achieving this?


Right, more days into this, more need for clarification…!

As far as I can tell, the IGenericTeamAgentInterface needs to be on the same Actor as the AIPerceptionStimuliSource (see UAIPerceptionComponent::ProcessStimuli, et al). Given this interface is defined on the AIController, it would seem to imply that the AIPSS needs to live on the Controller also. It would also seem to imply (if you’re planning on using the Team stuff) that either the Player has to have an IGenericTeamAgentInterface and appropriately overloaded functions, or the PlayerController does.

For consistency, it would seem sensible to stick everything on the Controllers (AI or Player), but I wanted to check whether this was the expected outcome (as to me it feels a bit weird - you’re “detecting” the controller, rather than the actual actor - is it guaranteed to be in the same location as the actor it’s controlling, etc etc).

Thanks for keeping me fed with info so far!

Gah! It’s almost ready, I think, just one request I have!

UAIPerceptionComponent::GetTeamIdentifier, change from:

return AIOwner ? FGenericTeamId::GetTeamIdentifier(AIOwner) : FGenericTeamId::NoTeam;


return FGenericTeamId::GetTeamIdentifier(GetOwner());

In the trivial case, it evaluates to the same thing, but for what I’m trying to do, it doesn’t rely on the AIPerceptionComponent being attached to an AIController.


Having a perception component on a player is not something we’ve considered. Usually players see and hear for themselves :wink: But I know what you mean and what you’d like to achieve. I solution that I’d go with in this case is implementing a dedicated PlayerAIHelperController (or something) and use that to gather perception data and feed it to player. I haven’t done anything like this yet, so there might be hoops to jump through, but I don’t predict anything major.

There’s no guarantee of Controller’s location being in sync with Pawn’s, so I suggest putting PerceptionStimuliSource component on the pawn. There’s is a slight mess related to show should implement the IGenericTeamAgentInterface, and we’re doing to fix it when we get a chance. A good workaround is to have both pawn and controllers implement it, and have for example controllers pass over the call to their pawns.

Ok, that sounds like a reasonable approach (duplicating the Interface). Thanks for the tip :slight_smile:

You’re totally right. I’ve noticed that while glancing through this code for the purposes of answering your question. I’ll look into applying this change - it might require couple of other changes like this one for consistency’s sake. Thanks for pointing it out!

I’ve changed one other line. In UAIPerceptionComponent::ProcessStimuli hostility-determining line should look like this:

PerceptualInfo->bIsHostile = FGenericTeamId::GetAttitude(GetOwner(), SourcedStimulus->Source) == ETeamAttitude::Hostile;

Awesome! Thanks for this, Mieszko!