General good practises to write performant blueprint code?

Hi,

So I’m pretty far with my project, but now I noticed that performance is terrible inside the editor when playing. I have 100+ blueprints and UMG widgets inside my project, and the performance is now terrible. when not playing the game or when in the main menu of my game I have 60 FPS. The moment I get in my playable level, and use my TopdownController, the FPS drops to 10-15 FPS.

So my first question is, how do you write performant code, are there any good practises to follow that you can think of that you maybe did wrong at first but now know how to do better?

i.e. I have alot of code where I cast to the same object multiple times. i.e. Get Player Controller -> Cast to TopDownController. Would it increase performance if I made references to the topdownController in the beginplay and then call the reference instead of casting each time? Now that I know more about blueprints it kind of makes sense that it would be more performant, so if I make references everywhere in my 100+ blueprints/widgets, will that significantly increase performance?

for my second question, I have bad performance inside the unreal editor when playing. it runs at 10-15 FPS. But when I package my game, it all runs smooth at 62-63 FPS. I can only find questions on google/answerhub that have the reverse effect, where it runs smooth in the editor but slow when packaged.

What might be going on here? why is my packaged game running at 62FPS, and in the editor only 10-15 FPS?

Thanks in advance!

In Software development, there is always the balancing act between performance and memory usage.
To have the best performance, you want to cache as many varibales as possible(if they are used multiple times) and as few function calls as possible, too.
Of course it is faster to have a variable of the explicit type instead of having a general type through a function call (getControlledPawn() for example).

Most of the time the difference between having a explicit reference and general Type+Casting is negligible unless you do it multiple times per frame.
Event based design is always better than Polling. Pretty much everything is better than polling.

My personal opinion:
I always take scalability and flexibility into consideration aswell. Which is why I make excessive use of Interfaces and neglect performance.
Interfaces in UE4 have the advantage that they get rid of Cast nodes (Interfaces Message Nodes), and It is easier to integrate into other projects (There’s so specific type, but only the interface).

Biggest tip: Limit the number of things on tick and when you can, manually set the number of times something fires per second. It can easily be done with timers by function or timelines; set to looping. So let’s say there is something you need to check the status of like enemy health, to update the UI or something. Rather than doing it every single frame, you could just set it to check every 200ms or so(5 times per second or “5fps”). Perform optimizations like that, across the board, and you’ll probably gain back a lot of performance.

Along those same lines, try to make everything event driven; if possible. When using timers by function name or timelines, you can easily start/stop/resume them. This can free up more performance as well. This is one of the main reasons why they made behavior trees for AI. It’s almost all event driven and you can easily set update/polling rates for tasks. A good example of this would be if you had 20 enemies on the screen: There is no reason why they should check your location and calculate a new path to you; every single frame. Nor is there any reason for them to scan super frequently when you’re far away or something. So you’d use an event to trigger their AI to drop their polling rate from something like 5 times per second to 1.

Thanks for the tips. More tips are welcome :slight_smile: I’m going to rewrite a lot of my code and want to do it right this time

What could help you aswell is to focus on the things, which absolutely need updating. Activate things only if necessary and try to keep your chains of nodes relatively simple. If you lose track of long chains of nodes, it is probably better to simplify them. You can always chain simple logic together to create complex behaviour and it will save you a lot of headaches :). What also works for me is asymetric timing. Call things in different intervals, so you don’t call them all in one time frame, because the PC might freeze up, create micro stutter or drop in fps. If you however distribute your calls on different time intervals, the PC will only need to process a portion of you game code at a time and will perform much better.

Just my 2 cents :).

Ok so I started using the profiler tool and found the bottleneck with my game.

I improved performance from 10-15 FPS to 45 FPS.

It was a stupid mistake where I didn’t set the size of an array. It worked, but it had to calculate the size of the array every frame.

Looks like, for now at least, I won’t have to be doing any rewriting of code :slight_smile:

thanks for the tips though guys, they are definitely things I will keep in mind with writing further code!

Profiler is definitely the way to go. Don’t rewrite code if you don’t need to, as preemptive optimization leads to code errors.

Best to write what works then use the tools to identify where too much time is being taken then fix what you can in those areas.

One thing to consider is that every node you place requires the engine to go through the virtual machine layer then back to native code. If you want to keep things on the blueprint level (I.e. not nativizing when building) or optimize for running in the editor then you may want to minimize the number of nodes you place. It isn’t enough to collapse nodes into a function or macro since all those nodes still exist, you must simply not place nodes when possible.

Due to engine overhead you will also always run more slowly in the engine than you would in a packaged game. And if it’s all the same, you should nativize when packaging - it’s so much faster in-game. Then turn off specific nativized scripts if it causes errors.

how do you do these timed calls? Since I have got things firing off one by one off the tick using a sequence node.

If you nativitze the Blueprint Code and turn it to C++ can the blueprint be undone once its been converted? Or do you lose the blueprint when it converts to C++ code?

pretty sure that only effects the packaged version…

One small thing I’ve noticed is you need to make sure you close all the open windows in the editor when testing in pie. If you have blueprints open you are working on and start the project. Memory is getting allocated as if your debugging.

All those pretty wires lighting up when events are getting fired actually consume quite a bit on a mid range machine, even having static mesh open in viewers act like having multiple worlds open so you can fly around them.

So just a heads up on that.

I tend to build out a project once in awhile through to play stand alone to see how it runs then as I work.

Cheers

  1. Saves casts to a variable and call that variable multiple times.
  2. Limit Tick functions - if possible use Timelines, they can be used as togglable, triggable ticks.
  3. Make sure your draw calls are low, ie limit the amount of triangles on screen. Having 100 100,000 polycount figures will slow any game down.

Call “set Timer.” You’ll have two options, either by function name or function. Then you set a number of seconds to wait between each call. Keep in mind that setting the number of seconds to be fewer than your delta time (the number of seconds between frames, at 60fps it’s around 0.016 seconds, at 30fps it’s around 0.033 seconds) will cause slowdown, it can only be equal or higher than delta time, and if it’s equal you may as well just put it on Tick.

It’s only nativized at package time and saved as a separate set of libraries that the game then calls into as opposed to going through the VM. Your blueprints remain intact, no need to worry about that.

I find this statement to be absolutely wrong on many levels… If you’re leading yourself into errors, then you’re doing it wrong. It’s fine to make a proof of concept, that’s inefficient, but after you’ve gotten it to work correctly, optimize it while you can. You don’t have to pinch it down to individual cycles or anything, but don’t leave something like a complex pathfinding for-loop on tick.

Always best to try to optimize as you go along. It’s better to do it THEN, than it is to play whack-a-mole LATER, when you’ve got 50k lines of code and 500 blueprints to sort through. This is one of the BIGGEST reasons why a lot of promising games end up terrible at launch: They waited until the last minute to optimize and got lost in an ocean of poorly optimized code, when it could have only been a pond’s worth.

Maybe it’s from where most of my education is in robotics, but we definitely learned that early optimization is the way to go and to compartmentalize tasks into their own tidy little packages; before “marrying” them all together. When you have poor coding optimization, that poor performance will bleed off into the rest of your design and make you think you have less wiggle room than you actual do. Which in turn can make you lower quality levels that didn’t need to be lowered. It’s kind of like efficiency(electromechanical engineering) in the sense than your overall efficiency can never be greater than your least efficient link.

I didn’t say to write a bunch of awful code, I just said not to optimize before it’s necessary. When your code is young, it’s very fluid, so a system you build in the beginning may not even work by the time you have code that’ll stick. Then you’ve just wasted time and muddied your code.

This is why we have profilers to identify bottlenecks and bumps in the road so you can target them specifically.

We’re developing video games in an engine full of profiling tools. We’re not writing firmware for a robot from scratch.

I’d still say that if you’re having that problem, then you’re doing something wrong and/or not planning ahead well enough. If you were designing a car, you’d know that you need a chassis, wheels, engine, transmission, etc etc. You wouldn’t just blindly start making a transmission without knowing what it’s input and output are going to need to be. That’s why you need to have your list of needs/wants/nice-to-haves etched out before you start working. Project management is an absolute must; when working with deadlines and complex projects. Take a month to fully hash out a game-plan. Get some logic map style software(I’d imagine tons of free ones out there) and start making the hierarchical web of things like loops and variables. Picture it as your pseudo-code. As you’re creating the actual parts, cross them out or fill them in with a color on the logic map(have a legend for what the colors mean like red:not done, yellow:60%, green:95%, etc). Modularity is also really nice to have and is almost an absolute must; for larger projects. Don’t make some system that reads seven manually set elements from an array, to populate something else. Instead, make it read N elements and populate N objects. Organization and templating like that go a long way. If you have something like a non-behavior tree AI BP, keep all of your tick/timers near each other and use events to jump to their location in the BP haystack. I could go on and on about tips like these all day, but you get the point: Organization and pre-planning are absolutely essential in pretty much any project.

Also, if you have some task and your current code isn’t working well for you or is becoming too convoluted, don’t be afraid to scrap it and start it over.

I’ll agree that profiler is great, but isn’t the be-all-end-all solution. It will give you a hint as to what is bogging you down, but it’s not going to directly tell you how or why it’s messing up. That part is still on you to find and optimize.

Well don’t rely on them to do your job for you. If you’re using them in tandem with good practices, it’s a win-win.

We’re saying the same things largely. I’m not condoning anyone write sloppy code. It’s unreasonable to expect everyone, especially hobbyists or bedroom coders, to have a complete picture of the code structure of their game in development.

I’m really not interested in carrying on this conversation. We’re off topic now anyway and making this thread about us.