Performance related question when dealing with large unit counts, strategy game.

*Before I dive into my own tests I thought to drop this here just in case. Thanks.

Anyone here with experience dealing with large numbers of units for a strategy game?

I’m talking about units in numbers of a 1000 on screen. Each one is meant to “see” the enemy counterpart and attack it. Each one shooting rays to detect the other unit and execute a command.

How’s the performance overall on something of this sort? any heads up on a particular issue I may run into.

Lets also assume I am not using AI to do this but rather a simpler BP function “go to target, aim and fire” How much of a difference will that make.

I haven’t seen too many strategy games or samples of this sort available or created in UE4 so I’m not sure what to expect.

It really depends :slight_smile:

  1. Blueprint in Editor (Poor)
  2. Blueprint in cooked development build (OK)
  3. Blueprint in cooked release build (Better)
  4. Nativized BP in cooked release build (Good)
  5. C++ in cooked release build (Great)

There’s tons of factors when it comes to RTS’, mainly how mindful are you with your traces, for example performing target search loops only every second or so, not every frame. Same goes for height tracing (adhering unit to landscape).

From my experience, by far the biggest killer of performance for RTS game is collisions. Even with physics disabled, just collision handling itself among units or between units and landscape can bring it down to crawl. If you use smart line traces to adhere units to ground (I trace every time unit moves X distance away from the last traced point) then you can disable collisions between the ground and the units.

Ideally, you could disable collisions between units all together, and use something like RVO Avoidance to keep them apart, however even that is not perfect. I settled for a solution of using RVO Avoidance combined with collision only between the units. RVO keeps them apart enough to minimize the amount of cases where more than two units collide, as collision cost grows by the exponent of the units participating in the single collision. If you have one blob of 50 units all rubbing against each other, the collision complexity cost is 50^50, which is just crazy.

The approach that worked for me well so far when creating RTS is to start from the nothing ever collides with anything state, and then very carefully introduce collisions between any sets of objects, be it static or dynamic, only when it’s really, really necessary.

It’s worked well so far for my game:

The absolute bottom line is that the lowest common denominator here is not UE4, but rather C++, which is very performant. So even large scale RTS is definitely possible. The difficulty of achieving it is whole another discussion though. The more unique the game will be, the more “bending with a hammer” will UE4 require, to the point where if you are skilled programmer, you may reach a point where you think writing your own engine may be a better way. I am nowhere near that experienced or smart, so I just use UE4 and so far it’s working well.

Also, you can push it to the extreme by going Deserts of Kharak way:

They’ve essentially build an external C++ application which does high performance simulation of all the units and their interaction in 2D space, and the game engine, in their case Unity, is just used as “visualization layer” to display unit movement and interaction based on the data supplied by that external, simulation layer.

Hey Rawalanche Thanks for this informative post! Also your strategy game is looking great!

I wasn’t expecting collisions to be a trouble maker, I thought traces would most likely be the thing to watch out for, I suppose if like you said I use traces firing a every other second instead of constantly, it may help.

Also in your samples you use a few dozen units, have you tried any with a 1000 on screen at the same time?

When you mention “Blueprint in cooked release build (Better)” or" Nativized BP in cooked release build (Good)" I suppose you mean simply building your game, UE4 will automatically convert your BP nodes to its own C++ variant anyway correct? There is also an option in the settings to tell UE4 to “Nativize BP’s” I think this is already enabled by default these days (got to check again)?

BTW I didn’t know they had their own C++ built for Kharak, I thought they used all native Unity with C#. Makes sense now.

Blueprint nativization is still off by default because it may not support some obscure things. So when you enable it, it usually requires a bit of changes to some of your blueprints to make them more nativization friendly.

I have done some simple C++ tests before I started the project and I found I can get about 2000 units moving smoothly without any issues using C++ components in UE4. But right now, my game is 99.9% blueprint, because C++ development and iteration is just brutally slow compared to Blueprint. So my plan is to figure out all the features and mechanics in BP, then once the game works fully, enable nativization, and do a cleanup pass, and after that profile, and rewrite only performance bottleneck parts of the game in C++.

I mean check this out. This is a cooked build test with about 1000 units, with NON-NATIVIZED blueprints. There’s literally almost no C++ code except one single C++ component which exposes RVO Avoidance interface to Blueprint:
Actually, I had to decrease unit spawn spacing to even fit them into flat areas of the map, so most of the performance drop actually doesn’t come from the unit count, but rather, as I said, collisions between them. That’s also why they behave so weirdly on move order, as collision depenetration kicks in. If this state of the game evolved naturally, the units would not start touching each other, so the perf hit would be that much smaller.

And despite all these unfavorable conditions, it still refuses to drop below 30 FPS. With pure, non nativized BP.

So the room for optimization for RTS games in UE is definitely huge.

As I said, when it comes to RTS’ in UE4, performance certainly won’t be the issue. The bottleneck will be more in terms of bending the for the kind of games it wasn’t really designed for.

This is awesome thank you for taking the time and providing this info very much appreciated!

Good read… Thanks for sharing…

Just to echo what was said. In stress tests, traces seem to be quite light on performance. Whereas MOVING complex objects through complex scenes just eats frame rate. So depending on your use case, you may also have to consider the collision complexity of the background scene. Merging meshes can make a huge difference if your use case allows. For this reason (and others) I tend to avoid UE landscapes altogether, as UE handles meshes much better…

My setup is TPS not RTS and uses aircraft as opposed to ground vehicles. So players need to be able to collide with everything all of the time: both static and movable. After about a couple of hundred vehicles using BP only, UE starts to struggle on a standard I7 / 1080 type spec (PIE). But 100 craft is enough to sell the effect, so it can be dialed back later before packaging.