AI Perception: Detecting the Players slows down significantly with the number of AIs in the Level

Hello Community,

i need help in improving the efficent of my AI. In my example, ever killed Zombie will be replaced by two new Ones. That way, the Game gets heavier over time.
The following video demonstrate how my AI is reacting to the player in the moment he comes in the Zombies View-Arc. Iam using the AI-Perception System for this.

In the beginning, every Zombie seems to react nearly instantly to the player.
At a DeathCounter around 19, you can see, that some of the Zombies even dont recognize the player.
At the End of the Video, you can see how that nearly every Zombie ignores the player. Even when i am trying to block their way.

I realize that the behaviour tree etc still runs even after the “death” of a Zombie.

After unpossesing the ZombieActor the result is much better. But still not that good:

In the second Video, you can see how the Zombies are spawning right behind me and are all ignoring myself.
I tried to “destroy” the “AI-Controler” but i beleave that this dont work correctly.
At the end of the video, i recongnize all these green controller (?!) Icons at the maps origin.

Do you have some advice for me?

At Night i came up with the idea how Friend/Foe Detection is maybe causing my problem with AI Perception. Because i do not understand how “Detection by Affiliation” works (specially how to assign an actor on one of the sides), i did checked all three boxes:


And filter the “friendly zombie” actors later in “OnPerceptionUpdate”:

The loop should be a hughe load to handle… iterate through all of the 100+ Zombies to look for the ONE/TWO/THREE Players. To me, it sounds very inefficent. Any sugestions on that?

I am still looking for help to get behind using “Detection by Affiliation” and those green smileys (representing either the controler or actor of the AI) at the maps origin after AIs death.

I am also working on a zombie ai system that is similar. what you should do is break the perception and cast to the the class of the actor you are trying to detect to see if it is what you want. On a successful cast you do your stuff and on a failed cast you can have additional behavior if you so choose.

You have to run a crowd system instead of each unity running their own AI calculations. Otherwise this will never have good performance.

not true, I have this running with 100 zombies at over 130 fps on my old pc. The ai perception system does seem to sense slower that pawn sensing for some reason. Using just pawn sensing my ai react instantly, but I want to be able to use other senses that the ai perception system has.

Well sorry but he is right, the more zombies you have the heavier AI Calculations will be

Hi [USER=“34762”]Manuel Ott[/USER],

I answered a question a few months ago about this very topic here: how do i use the ai perception teams . The long and short of it is: You can’t use this system very well without some C++ setup work.

We can however do some quick work to improve the performance of your solution. Your “OnPerceptionUpdated” event handler calls the Get Currently Perceived Actors call in a loop. Since it is a Pure function call, that array will be re-created on every single execution pulse of that loop that uses it. Call Get Currently Perceived Actors only once by storing it in a variable / local variable, then referencing that. You can also save a few nodes / execution pulses by combining the 3 Branch nodes into 1 by using a boolean AND of your three conditions.

Thanks a lot to help me even after two years :slight_smile:

Getting the IGenericTeamAgentInterface to work reduced many calculations.

Right now, I am working on the successor of this little project and it is fully C++. But currently, I am not working on the AI. At first, I need to be able to shoot :slight_smile:

I’m not sure I follow this entirely. Makes sense storing in a variable and running off that ( which you can obviously add to the array any new unique actors ), but what do you mean by calling it once?

Pure function calls are not cached in Blueprints, so if it returns an array with 10 entries, then the function would get called 10 times, once for each entry. Essentially redoing the work more than it needs to. It’s a bit of a trap that’s not mentioned anywhere.

By storing it in a variable, it’ll only be called once, instead of recalled on every loop iteration.

You could always try not giving Zombies perception.It depends on what you want to do, of course, but you can just a easily do it in reverse. Put a perception ring around the player(s), which will give a you a single list of zombies close to the player, rather than having a hundred perception systems running simultaneously. This doesn’t work in every case, obviously.

In my case it’s not exactly what I want since I’m working on a Utility AI system. The more I dig into perception the more I just want to build my own component. I don’t understand why this set up is so wonky or why they are depreciating Pawn Sensing. It’s really odd.

Whats even weirder is If I disabled the auto register pawns as stimuli source, so that the ai only see the player, IT’S THE SAME PERFORMANCE AND REACTION TIME. I can clearly see in the AI debug they aren’t looking at other actors though. Something somewhere is just not right.

Here’s a bit of what I do with the UAI:

I’m dealing with this as well.

I had one solution working, but there’s holes in it. I put the AI Perception onto my Player Character with a 300 radius and 400 dropoff radius, but now 90% of the AI’s that are actually in front of me (who are perceiving me) I am not perceiving, so the AI Perception engine is actually “broken”. It’s literally bugged.

If AI Perception says 300 radius / 400 dropoff and I have 3 AI’s in front of me at 100 radius, I should perceive them — but as I said, only 90% are perceived regardless of their distance.

It results in invulnerable monsters because my hits do not propagate to them when I iterate my perceived AIs.

So I am probably going to have to just write something “get all actors within X radius” and rule out non-enemies when I hit them.

PS: every step of my game so far I am having to watch tutorials to do things, so I’m learning no matter what I do (ie: noob).

I know I’m a little late to the party, but, I had the same problem and wanted to solve it without spinning up my own custom sense or other logic which would then have to pipe-into the perception system somehow. Upon examining the source for UAISense_Sight, I saw the constructor initializes several variables. Two of which caught my eye:

  • MaxTracesPerTick
  • MaxTimeSlicePerTick

Looking at the definitions of those, I found that they were defined with the Config UPROPERTY specifier. I set my values astronomical, but, this immediately improved the “speed” of perception with no discernible frame rate difference. For reference, my scene has over 150 AI’s.

DefaultGame.ini (in my project’s Config folder):


I took the defaults and multiplied by 100 just to make sure I was actually touching the right variables and that’s much easier to do when you make orders-of-magnitude changes. This works for me (so far) in 4.25.1 and now there is no hesitation on the sight sense. Hope it helps someone else.

Also late to the party, but i use this system as well and just don’t seem to have that issue (perhaps i do and just haven’t noticed :D, i only have about 100 ai’s at a time…)

im on 4.24.3
Looking though aisense_sight cpp and .h i see values

Values set from the top of the cpp:

static const int32 DefaultMaxTracesPerTick = 6;
static const int32 DefaultMinQueriesPerTimeSliceCheck = 40;

in the init it does the following:

UAISense_Sight::UAISense_Sight(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, MaxTracesPerTick(DefaultMaxTracesPerTick)
, MinQueriesPerTimeSliceCheck(DefaultMinQueriesPerTimeSliceCheck)
, MaxTimeSlicePerTick(0.005) // 5ms
, HighImportanceQueryDistanceThreshold(300.f)
, MaxQueryImportance(60.f)
, SightLimitQueryImportance(10.f)

My question,
How is your performance after your changes? have you done any profiling? Upping max traces shurely has a negative impact on performance… :smiley: