For the sake of discussion I’m working on a tower defense adjacent project. There will be a ton of projectiles on screen at once.
In general: What is the most performant way to handle slow moving projectiles? Line traces with Niagara effects, Actors with transform timelines, or something else?
Specific question: I have a building that drops a boulder which bounces twice and rolls. Should the boulder be a static mesh with transforms to make it bounce/roll? Or should it just be a static mesh with a looping roll animation?
I need maximum performance because of how much is going on in this project. There’s not much info out there other than grouping ticks, reusing actors etc.
I am working on RTS with a lot of actors so I can share my experience.
Avoid skeletal meshes - every skeletal mesh, autmatically spawns more stuff to handle it
Try to pack all of the changing transforms in least possible nodes/calls. Grouping ticks is one way but also don’t split up set location / rotation / scale to different calls. It may sound obvious, but I did split them sometimes for code readability or I just wasn’t thinking about it.
Avoid many components in actor that moves - every component calls it’s own transform change.
Timelines are heavy becuase they are separate components, moving with tick is better, grouping ticks in one manager is a lot faster, but ticking from c++ is always the best.
In the end, changing transform is heavy itself, so just try to not update stuff you don’t need to. ie - you have projectile that goes offscreen - update only it’s collision component (or the other thing you use for detecting hits), don’t update visuals, static mesh / particle transform.
Don’t loop trough hundreds of anything in Blueprint. It’s a bummer but BP for loops are extremly heavy when big (the performance cost grows exponentially with the loop size).
Either use C++ loops, or cut loops to chunks (less than 100 would be ok I think, I didn’t test it explicity). Or just be creative, a lot of times you probably don’t have to loop trough everything.
and you can try to use Instanced static mesh if you have a lot of the same meshe everywhere. It could boost performance a lot but it’s usually the pain to work with and can lead to some unexpected challenges.
Dont stick to one solution - make a base of your projectile, but be prepared for branching it to different childs. I would deffinitely make Boulder example an Actor with static mesh and stuff, but making a static mesh for a Laser that hits target instantly seems like overkill.
There is this saying not to optimize prematurely. Make a prototype, spawn an extreme amount of everything and run it with profiler as fast as posisible. you might be suprprised what is costly and what is not, it might save you time.
Thanks so much for these tips! I have a large grid of structs from which I’ve created my pathfinding, collision etc. I have created so many loops it’s insane - Any suggestions for cutting these down? I feel like they are unavoidable… I guess I have to explore the c++ side of things.
So far I’m able to spawn 500 units with skeletal meshes doing pathfinding & 400 towers while keeping above 40 fps. I plan to have 8 players so I need to improve.
If you have your prototype ready that’s great, because now you can ignore my tips and check what is taking most of the resources in your specific case.
Use Unreal Insight or built in profiler
The first is the best tool to profile, but you need to learn how to use it.
Profiler is much easier to pickup, but might be less accurate.
Both tools need some time to learn, and a tutorial or two, but you won’t regret it. Honestly I was frustrated at first, but as I got comfortable using them, it turned to be quite a fun, really.
I’m just always surprised about some cases I would never found out, and also I’ve learnt a lot about do’s and dont’s this way.
If for any reason you just can’t or won’t use these tools, use STAT commands to get a quick grasp what is the biggest problem. For example Stat Game, Stat Tick, Stat RenderThread, Stat Quick etc (all of the stat commands here)
But be aware - using only stats for profiling might be misleading.
About the loops:
C++ will help a lot. I know the pain (I’m still feeling it, started to learn it about a year ago) but the faster the better.
I was also making chunks of array. For example, create 10 arrays, and each object add to next array. Then in each tick loop trough only one array at the time.
But honestly - I wouldn’t suggest any of the weird solutions now.
You should locate your biggest problems and deal with them, and build your game around your specific needs. Profile your game from time to time to stay updated.
Always keep performance in mind, but don’t do hardcore stuff at early stage, it will get harder to work with, and also might stale your production.