I am interested in making a shop UI that appears when interacting with a specific placed actor. Initially, I was thinking it should be placed on the actor that brings up the menu and could be added to the player viewport via an interface. Alternatively, if I put it directly on the player, I feel I would still get to the same outcome of having the widget attatched to the viewport, but it might be easier to add items to the player inventory since I am already on the player blueprint. Is one of these more practical or is there a better option than both?
In either case, would it be better to make and delete the widget each time it is used, or just adjust the visibility? For hud elements that are frequently used, I think visibility would make sense, but for these more niche menus, I am unsure what the best approach would be since adjusting visibility may mean having several rarely used hud menus constantly on the viewport.
There are many approaches to it, depends on the need, use case and quality of it.
Here are some examples done in blueprints, recently done in forums as demo with interfaces and components.
These are the interactions .
In terms of your underlying questions.
1- Should UI be player side or interaction side ? Think about the interface and interaction as two different systems, they don’t have to tell something to each other. Interactions can be authored on player (interactor) side, that would be the appropriate approach. If a menu needs to be opened interaction system on player can tell this and hand over to the UI. UI shouldn’t be authored there, it should author itself. When a menu no longer is needed UI logic should do removal without the need of the interaction event. Also this approach would be valid in multiplayer too and more controllable. Actor UI couplings is not a good practice, it can be perceived as more work but in long run it would be less work.
EX: Interaction/Dialogue/Shop menu instigator != valid, in range, or instigator reference changed then maybe it can be a good time for the UI to auto close itself.
Subsystems are the correct home for these in modern unreal terms but depends on scope. For larger systems push, pop, pull layerings are common practice.
EX: interaction dialog(talk)->DialogueMenu(Barter, ask directions,etc)->BarterMenu
Interaction and dialogue are hidden collapsed and hold at stack in background when BarterMenu introduced.
Barter menu closing destroys it( less used / loaded)
Interaction dialog pops (since we are still in range as assumption).
2- Performance wise which one is better? A commonly used UI can be visibly collapsed rather than destroyed and reused like a pool. This can be a small widget like “press E to” or a bit bigger one. I don’t recommend bigger ones since it feels like a good idea but inventory menus, barter menus can contain many references and additional memory links so a working menu with complex logic can better be closed since if the logic changes it can throw errors or even crash things. A common practice in interfaces is not to hold state driven menus long time for no reason.
Another thing to add there is big difference between hidden vs collapsed in menus, collapsed doesn’t tick in slate, logically have no space allocated in render so use collaped not hidden as common practice where applicable.
Recreating it every time is much simpler and better for the performance And then you do not have to check the the old state is not present for example if the new shop has more items then the last one. Simply recreate and add to viewport and give the player a reference to the widget or the widget a reference to the player, then you can directly handle the things that the shop changes in the inverntory of the player
Just to clarify, by “actor UI coupling” you mean associating a given UI with a specific actor rather than the player themself?
As far as prompts go, I feel it makes sense to just hide/collapse something like an interaction prompt in my context since it will get a significant amount of use. The shop menu, however, would seem like it should be destroyed once no longer relevant (i.e. out of the interaction range). Assuming I go this route, how would I go about actually removing the widget? I know the remove from parent node can remove it from the viewport, but I am confused whether this actually makes a difference. I will need to reference the widget class to create it, as well as the actual widget object to make dynamic changes to its appearance. Wouldn’t this mean that removing the widget from the viewport would still have the same impact on memory since it is hard referenced or is this not true?
Is there a distinction between having a hard referenced asset in memory vs that specific asset being placed in the world/on the player? I think I probably don’t completely understand how this works.
Yes actor UI coupling is basically like that. Its not a good practice but its not a sin either. It can quickly get messy though since many actors start having UI logic on them and then managing that lifecycle becomes annoying.
Usually better to keep UI player side and let interaction system trigger it. Actor just provides data or says “hey something is interactable here”. UI decides when to open/close.
About removing widgets RemoveFromParent just removes it from the viewport. It doesn’t immediately destroy the widget object. Unreal GC will clean it when there are no references to that instance anymore.
Also there is a difference between referencing the widget class and the widget instance. Holding the widget class (the blueprint asset) doesn’t keep instances alive. Only references to the widget object created with CreateWidget do. You can think like this. lets say in bp you have a widget refeerencee in bp thhat is not createed yet. you cann make a lot of changees in it without spawning but wheen you spawn its when aactuaally creaated and consumes signinificaant memory. By significant : widgets are generally lightweight however cost is a cost and cost.
For small and frequently used things like prompts it’s fine to just collapse/un-collapse visibility. For bigger menus like shop / barter I usually recreate them when needed and remove them when done so they don’t keep old state around.
Also in practice widgets are relatively cheap, the bigger problems usually come from keeping complex menus alive with a lot of references and state rather than just recreating them when needed.
Thank you! This has been extremely helpful. I now understand the distinction between the widget class and instance. Is there a good way to know when a widget instance would no longer be referenced then? Assuming I have promoted the widget instance to a variable on creation, would I need to clear this variable somehow to meet this requirement (and if so, how would I do that since I can’t just make a null variable for it since it is a specific widget and not a base class of some kind) for Unreal GC to remove it? Alternatively, is there a way for me to identify when something is cleaned by GC?
My pleasure, I am glad that it helps and I totally understand that it can be confusing sometimes.
Well in editor there is a memory inspector you can check, however more accurately Insights and GC logs will help but the main rule is quite simple: if there are no references to a widget, with some delay the garbage collector will completely remove it.
So lets imagine that you have a UIManager, some class, maybe a subsystem, but for now lets assume it’s the player controller.
This UIManager has a function like AddContentToViewPort(Class). This function when called creates the instance (CreateWidget), adds it to the viewport, additionally gets the instance reference and adds it to an array named CurrentCreatedWidgets.Lets make another function RemoveLastCreatedContent(). This simply gets the last entry in the array → RemoveFromParent() → then RemoveFromArray.
Player does something in the menu and eventually closes it.
If closing is done from inside the widget with RemoveFromParent, since the player controller still holds it in an array as a reference, the widget will actually never be destroyed. It will stay in memory.
If closing is done from a function in the controller, lets say RemoveLastCreatedContent(), this would clear the references connected to the widget and eventually when garbage collection runs it will be gone.
Even sometimes RemoveLastCreatedContent() can have an additional ForceGarbageCollection() to immediately do the removal. This is not a good practice in gameplay menus, HUDs etc. However it can sometimes make sense on state-driven menu panels, menus that cover the screen and where the player can only interact with this (like pause / options menus) since the load on the game thread is more stable, leaving some room for a forced garbage collection.
Garbage collection is something unique. I don’t know super deep how it works on engine level but I know it tracks certain timings and game state to trigger a collection, so it decides a bit by itself. It is good practice to leave it alone most of the time (not always). It is expensive and can stall the game thread. I also don’t want to misdirect you about garbage collection but you can see some useful information in the Insights window.
Also as spice from my side: Don’t know how you are into it or your skillset focus but if you are going to deal with this thought it can be a good idea to share some tutorials.
If you are new into interface systems, technical ux, interface architecture and you are into it (not knowing your background) there is a lot of documentation around topics in many different development environments. Still I should warn that not every advice is meaningfull and helpfull in the long term, majority of tutorials are shortcuts, so I strongly suggest making mistakes, learning from mistakes is the best experience ever can be. However wisdom is always something to seek and find.
With that said accessing the right information and evaluating the architecture and approach becomes very important, its not very easy nowadays to navigate correct information in the sea of information. UI systems can get quite sophisticated and mistakes there can severely affect UX and even gameplay. Unfortunately this is quite common in UI development even in experienced teams.
Here are a few tutorials that can help you kickstart things.
This one is brief but a nice starting point.
Blueprint approach that is still scalable and proper. Seems leans on more default engine components and features more as a series of tutorials
C++ example, you can just skim it for the general approach.
I am mostly just working on a project for fun right now and to learn the system, so I don’t feel like I am experienced enough to necessarily need to perfect this specific system until I am more familiar in general but I think this will certainly be enough information to move forwards.
Looking at that first video, I feel it make be more sophisticated than what I reasonably need for my system as I don’t plan to have a significant amount of UI popups. I have looked into the concept of widget stacks but have had trouble with implementation as I am interested in making a local split screen game. I have run into a lot of issues with simultaneous gamepad/mouse usage as well as widget focus (which seems to be forced when adding a widget to a stack).
I like the idea of storing in an array to keep everything organized and provide an easy way to clear widget variables when out of use, however, in order to make this, I think I would need to store all widgets in a regular widget object class and then cast the class to the specific widget class when needed in order to get variables from that specific widget in order to make any kind of dynamic changes during gameplay. Alternatively, I could use soft references in a generic widget array without casting and then modify UI dynamically by calling functions in the widget blueprint itself using interfaces (which I am now realizing is probably the better way to do this rather than making modifications directly from the player blueprint). For example, if I have something like a shop menu and want to change an image, I would then interface to the widget and modify it directly in the widget blueprint (and this would also decentralize a lot of the functionality from being stored directly on the player blueprint). Does this sound like a more appropriate solution? My main concern here would be controlling when widget modifications affect all players vs only the player causing the event since modifying the widget itself would presumably affect all players (I would need to test this though)
Storing them as UserWidget references in an array is perfectly fine. Calling functions on the widget itself to update visuals is generally cleaner than having the player blueprint directly modifying many variables. You can even have a shared blueprint function library for those maybe. Casting when you actually need a specific widget is also normal practice, nothing wrong with that. If you are worried about sizes, it’s not a big issue unless some big classes are hard referenced to each other.
Soft references of course are good, however in blueprints they are mostly for loading assets, not a required principle if you already have dependencies. Example if you have a dynamic widget, and there are some steppers with long array images etc, or you will load some player icons that is not used right now but can be used in the next steps, after construction you can always lazy load those in background while player is doing something in the menu.
A blunt example is a carousel where swaps on demand, can be an image, can be a whole widget. You pre-load or start loading next and previous assets in the background if player takes an action they are shown without wait even loading, this makes ui responsive in general while lowering overall asset memory. (Very good for maps)
About affecting all players: that would only happen if the same widget instance is shared. In split screen usually each player/controller should create and own its own widget instance, so modifying it would only affect that player. So if you do the base structure of UI authoring on the controller, in the long term you shouldn’t have issues around this.
Also I wouldn’t worry too much about perfecting the architecture right now if this is mainly for learning. Starting simple and iterating on it is usually the better approach.
I got a chance to try this out and it works perfectly. It simplifies my player blueprints a lot and it also makes me no longer feel like I have a hard limit to the number of UI elements I can incorporate since I can now just unload unused ones. Thank you so much! This information really has been extremely helpful and most certainty saved me a lot of time on needing to make revisions in the future. You have absolutely answered the original question.
One final quick question. I currently have a singular canvas panel that I now load my new widgets (each without a canvas panels of its own) onto the viewport. I know that it is possible to drag a widget directly into this canvas panel main widget. Is there any real reason for me to do this outside of convivence? Organizationally it seems to make more sense to me to keep them all completely separate, always have this one canvas panel widget loaded, and load and add the new ones separately as needed.
Making the heavy work on canvas and in a Main Hud / Container is the right approach. The child widgets if they don’t require a canvas don’t use thats correct and add them to widget via common templating functions/approaches or as you see fit.
Some people (rarely) object to canvas even using single ones, don’t bother with it generally its just a tehnical point of view not a reality point of view with hands of interface experience. Canvas gives absolute positions and anchoring , its necessary for many games, even sometimes not enough for over the top AAA layouts where you need sometimes to keep aspect ratio, scaling apart from the devices, in that cases multiple canvases could be required maybe even extended ones. If nested canvases are very common in widgets maybe templating solutions , grids and architecture of the general layout and widget handling can be changed. If you have these kind of a setup like hud widgets coming in, changing etc. you can take a look at grid systems.
On the other hand I can just say that you don’t have to be a shaky hand with using canvases in general however if you can escape it in terms of the architecture, do neglect using it.