Hard references to widgets in HUD

Hello,

I use the HUD class as a bridge between the player controller and the widget classes (is it a good practice?). In this class, I have multiple (more than 20) hard references to different widgets. They can be removed (Remove from parent) and recreated if they are null. Should I make a blueprint interface for each one of them to avoid hard references?

Hello @bj_to0

I don’t think using interfaces would be much of a improvement, since you are holding a reference in a variable, which will block garbage collection.

You could make a dedicated manager (something like your HUD right now) as a actor component that you could attach to your player/controller, and use that to handle calls for your widgets. You wouldn’t store anything, just remove and create widgets as and when required. They are mainly for visualizing data, they shouldn’t hold anything important or game critical. You can take advantage of interfaces to handle communication and avoid unnecessary hard references.

I believe even when you Remove from Parent but store a reference to said widget in a variable, it still has the same memory cost, so having all of them in memory is just costly. Depending on scenario it might not impact performance in a noticeable way, but I would suggest you take your time when designing this system. In the end it should be more time efficient, since you won’t have to constantly keep going to it, when things will break or you need to add something new.

Also it’s not like you shouldn’t store them in variables, you absolutely can, just be mindful of possible reference chains.

I think you could make a “handler” function that you could feed various information and class of widget to be created. For destruction, perhaps you could implement self destruct logic upon certain events.

It’s really just speculation since I don’t see the big picture (only you do :slight_smile: )but having that many references just sitting in memory, might not be the best choice.
Problem being is said references also have references to other components / actors, and said actors hold more references, things can spiral out of control pretty quickly and it’s a chore to clean it up.

Hope that helps. if you have more questions, I’m happy to help. Have a great day.

This question of is kind of open in a “best practices” kind of way so take any response with a grain of salt. Mine in particular - it is based on my personal experience and is incredibly subjective. Ok, with that out of the way…

  1. Don’t use a HUD (or master widget) to handle communication
    Seems like a good idea at first - all logic in one place. Incredibly hard to scale up. The moment you have 90+ custom events and twice as many functions you quickly realize that dealing with everything at once is the worst approach. (you are probably feeling that seeing the number of references)
  2. Number of hard references is not the problem
    Hard reference to small objects that don’t need external information to be loaded is totally ok. Chances are, its not the references that is the problem here.
  3. Avoid creating and destroying (remove from parent) widgets runtime at all costs.
    Widgets are best created in the designer (or on create) if their max number is known. Widgets can be hidden or collapsed and in both cases they are not rendered and don’t tick but can access them and retain their state. Hiding/collapsing has incredibly low performance cost unlike removing from parent.
  4. Interfaces are not needed
    Interfaces are used to avoid too complicated inheritance for vastly different objects. These widgets should be pretty simple. If they are not, it’s not the interface that will fix that. Still, having interfaces will not avoid the need to get their reference.

Bonus since you read all this:

  1. Although I largely agree with @DonBusso I hate managers with passion
    They are useful design pattern but form the last 20 managers I’ve seen all of them are either not used correctly, breach the separation of concerns principal or/and are drag on the performance altogether.
  2. Make 1 to 1 widget → object/component/aspect link
    Each widget takes the object it is responsible for visualizing and accesses the object’s data directly. The object doesn’t know for, or access the widget. The widget knows everything about the object and manipulates it directly via hard reference and binds to important events.

Happy coding :slight_smile:

1 Like

i’d disagree with this a bit, if a character wants to OpenInventory there is no need to it to know about your HUD/Inventory/Item widgets etc

you can use a very simple interface like ToggleWidgetByGameplayTag and handle it wherever you like. but i use a c++ base class since you’ll likely need something like this in all projects.

there are alot of common functions you’ll reuse and you DO want it centralised since say if you open inventory it should close other widgets on that layer (ie skill tree, character sheet etc)

I think we are on the same page here.

I just don’t see how an interface (or in that matter inheritance) would alleviate the need of a reference to an object. You would still need a pointer to that thing to access it. Now weather that ref is hard or soft depends mainly on weather it is readily available.

well you only need the base class or even a UObject* if using an interface. So it doesnt drag in all the child widgets.

i know you hate managers but the way i do it is to have a MainHud as an empty canvas panel. add a few helper functions like PushContentByTag, ToggleVisibiltyByTag. etc and now i can reuse it in all my projects

Thanks you all for your contributions, I really appreciate to read these different points of view. I won’t comment what has been previously said but would like to add a quick related question, to understand your thoughts through another case. If I want to execute an event in the PC from a widget (after clicking a button for instance), how would I do it? OnClicked → GetOwningClient cast to MyPC → Event, or something like OnClicked → GetOwningClient → EventInInterface that will be implemented in the PC?

1 Like

either is fine, or even an actor component as a proxy interface. it really just depends on your game and if you want to reuse code in other projects.

for most indie games none of this really matters as our scope isnt that big, it just about learning good practice.

i would say do whatever gets your game completed fastest :slight_smile:

that said an interface or even GameplayMessageSubsystem is probably the best way.