Hi, Ive been using UMG for a while now and can create quite complex UIs with it but I’m just wondering about best practises for optimisation and whether my intuition when creating UIs is right.
Unfortunately for now delving into C++ is not an option for me, although i do understand it would make some aspects quicker.
So heres some current rules i try to stick to.
UI is as decoupled as possible from any other blueprint or code, I make the widgets fetch the data they watch rather and pass variables to it.
Separation of concerns(same principle as coding). I try to keep individual widgets quite light on the functionality side and create generic widgets that can be reused for multiple things.
This usually mean I have a lot of different widgets to be add/removed to the screen and to other widgets depending on what is needed, but I’m not sure on the optimal method for doing this.
Currently for widgets that are called on demand by the player (opening the inventory), I use AddToScreen/RemoveFromParent with the Construct event starting the initialisation chain, spawning any child widgets then binding to any necessary events.
I use widget switchers when possible for menus/shops and such.
Widgets that are often shown/hidden from the screen (think hover text type things), instead of adding to screen and removing from parent I create once and then set the visibility on/off. Thinking this would reduce the amount of GC.
Also because I used decoupled widgets there tends to be a lot of event bindings to allow for flexibility, but i understand it is better to directly set a variable when possible although it rare i often know where the data is coming from.
If anyone has any pointers, or links to optimisation tips it’ll be greatly appreciated.
I’m not sure that de-couples things. It actually pushes game implementation details into your widget blueprints.
I prefer a UI that knows nothing about the game outside itself, and use a set of variables, events, and interfaces to put a seam between the UI and the game.
Any part of the game that wants to use a particular piece of UI, will have to create that UI, hook it up, and use it.
In the end, there is necessarily coupling here – either the game has to know about the UI, or the UI has to know about the game. I prefer treating the UI as the dumb thing.
You can build a Widget that has UserWidgets inside it. That way, in the end, the UI for “display loot box contents” or “search for available network game” or whatever is a single blueprint that the game can deal with; that blueprint makes use of smaller blueprints that you develop separately.
Finally: Measure your actual game. If it runs fine, you don’t need to optimize.
I agree here, though it wasn’t clear to me that Lankeytom was necessarily saying his widget blueprints had a hard dependency on game blueprints.
With UMG, I think the main mistake people make in terms of performance is using too much data binding, just because it’s often the easiest way to set things up. On the whole, UMG bindings will be polled every single frame. Not only that, but the evaluation process is pretty slow, involving multiple levels of delegate calling. So whenever you have data that is not constantly changing, you are much better off having the game notify the widget blueprint of a change in data, and then having the widget blueprint directly assign the new data to the widgets. For example, with a text block, call the SetText method when you have updated text, thereby bypassing the need for delegate polling entirely.
My mistake for not clarifying I suppose, I try to keep the UI out of the game and the game out of the UI as much as I can. When I say the UI ‘fetches’ the data this is usually using events/interfaces or variables set when the widget is created.
I use this to try keep data binding minimal where possible as that all runs on tick.
My main concern really is whether adding and removing widgets from the screen would create any problems through the previous widgets being GC’d, using this method though initialisation can be done off event construct rather than creating and calling a custom init fiction with the show/hide method.