Say I have a variable in my GameState called Quarter and it’s an integer. I have it set to RepNotify. It creates a function in my BP_GameState called OnRep_Quarter, which is great. But the Blueprint that contains my actual scoreboard widget that I need to update is not in my BP_GameState, it’s in my BP_Scoreboard. What is the recommended or most efficient way to have that OnRep_Quarter function tell my BP_Scoreboard event to update the widget with the new value in Quarter?
I could store a reference variable in BP_GameState to access BP_Scoreboard, but that seems awful and incorrect. I could create an event dispatcher in BP_Scoreboard specifically for this. But that seems really tedious. It feels like there should be something built in specifically for this purpose. What am I missing? I feel like I want to just move OnRep_Quarter over to BP_Scoreboard but that doesn’t seem possible. But I thought I was supposed to store my gamestate variables in my BP_GameState! Do I really need reference pointers to all my blueprints in BP_GameState? That seems weird.
Solution A.) Use dozens of EventDispatchers (because I’ll have dozens of variables)…
Solution B.) Put pointers to all my relivent blueprints in my BP_GameState so I can just grab the pointer and call the event/funciton directly. In this example, BP_Scoreboard.
Solution C.) ??? I feel like there should be a more elegant solution here.
The proper way is to let the UI bind to EventDispatchers. They function similarly to delegates and are the recommended approach for UI interactions. The main idea behind this is to decouple the game logic from the UI. Using EventDispatchers ensures that you don’t maintain direct references to widgets.
Another option is to use BIND delegates on UI elements, but this is not optimal performance-wise, as it triggers updates on every UI refresh.
In some cases, you can use the same Dispatcher to update multiple variables. For example, if you have a HealthBar, you could use the same Dispatcher to update the health when either CurrentHealth or MaxHealth changes, but this depends on the specific use case. Hope this helps!
This makes sense. But this just seems like a lot of overhead. Because let’s say I have to do this for 50 different things. That means I have to do the following procedure 50 times right? It’s almost easier to have direct references than it is to add all this overhead…
With EventDispatchers I need to:
1.) Make the variable & set is as RepNotfiy. Let’s call it Health
2.) This creates the OnRep_Health function, which i hook up
3.) Go into my UI (in my case, BP_Scoreboard) and create an event Dispatcher.
4.) In BP_Scoreboard’s Event Begin Play, I need to bind to the event dispatcher
5.) I also need to create another event that will be called when the Health changes
6.) Finally, I still need to maintain that reference to BP_Scoreboard in my BP_GameState class.
So the question is. Does avoiding the direct references help performance, or is this just a housekeeping thing. Because it really feel slike robbing peter to pay paul here. On one hand you’re removing direct references, but at the cost of adding so much extra stuff that you have to maintain.
So maybe the only real advantage to event dispatchers is the modularity of everything in the long run? Does it make anything going forward easier or better? I’m just trying to better understand the benefit, because it looks and feels visually over engineered to do it this way.
The situation I think you’re working with is you have a GameState which has a dozen or so variables you want to display to the player via the ScoreBoard. You’re not wrong, this is a very common situation but there are multiple ways to solve it as different projects have different needs. That said, you essentially have 2 models (or a combination thereof) to work with.
Model A
Your GameState has a bunch of RepNotify’s, from which you call out to the ScoreBoard to update the appropriate piece. This of course means you will need a reference to the ScoreBoard…not a bad thing.
Model A (version 2)
Your GameState has a bunch of RepNotify’s, from which you create call an event dispatcher for each. Yes you’ll have more functions but now anything can bind to the event and get updates, not just the ScoreBoard (if that’s something your project needs)
Model B
Your ScoreBoard periodically updates (via an event timer) itself with the current state of the GameState…say every quarter of a second. The ScoreBoard could have a reference to the GameState (or gen one on the fly)…again, not a bad thing…and update its display.
The obvious benefit of A over B is that you’re only making changes when changes occur vs B which is running every quarter second to update things which might not have changed at all. Generally speaking the guidance for this situation is RepNotify.
IMHO EventDispatchers, while good design, might be a bit overkill for this situation. That said, there are benefits, as @BRGDemianLopez pointed out, if you had multiple consumers (so multiple places that needed to reflect the change), you would only have to make one call and have all pieces attach to the event. The example setup you showed is not what I think @BRGDemianLopez meant. Essentially your GameState should have an event which you then call…let’s say QuarterUpdated. Your scoreboard would then bind to that…maybe on begin play. Then you would just call the event, no need to reference the ScoreBoard.
This of course means you will need a reference to the ScoreBoard…not a bad thing.
Thanks. I was wondering if this was normal.
Model B
Makes sense. I’ll go the event driven route rather than the event tick route.
IMHO EventDispatchers, while good design, might be a bit overkill for this situation
That’s how I felt too. But I’m really posting here for the learning experience rather than just trying to “get it done”. So I appreciate all the feedback you all have given.
EventDispatchers…there are benefits… if you had multiple consumers (so multiple places that needed to reflect the change), you would only have to make one call and have all pieces attach to the event.
Yeah, that makes perfect sense. So my project is already using Event Dispatchers for that exact purpose, where I have it being called in multiple places across the project. In this case, it’s really a one off. So it sounds like the choice is up to me to choose whether or not to do it the “right” way or take a temporary shortcut.
The example setup you showed is not what I think @BRGDemianLopez meant. Essentially your GameState should have an event which you then call…let’s say QuarterUpdated. Your scoreboard would then bind to that…maybe on begin play. Then you would just call the event, no need to reference the ScoreBoard.
Thanks for pointing this out. I didn’t understand that. So when you say “have an event” are you saying to create the event dispatcher in the BP_GameState? Where as in my screenshot above I created the event dispatcher in BP_Scoreboard… So I did it backwards, is that right?
References don’t affect performance in terms of CPU or GPU, but they do create dependencies between blueprints.
This means that your GameState depends on your widgets due to the reference, so every time your game loads that GameState (for example, to use it on a particular map), it will also load the Scoreboard widget, which impacts memory.
You can use the other method (calling directly), and it will work fine. If you’re prototyping and want to quickly test functionality, it’s also OK. If your project isn’t very large, it’s not a big issue either. However, keep in mind that creating dependencies can lead to problems in medium-to-large projects.
My recommendation is to avoid overusing references. You can use them for your GameState if you have many variables, but try to use dispatchers whenever possible.
I’ve worked on projects with many blueprint references, and we had an issue where loading the main menu caused the entire game’s assets to load.
I just tried it with the event dispatchers in the GameState instead of the scoreboard and it’s so much cleaner. Yeah it’s more stuff, but being able to NOT reference BP_Scoreboard in BP_GameState is exactly what I was trying to accomplish. Thanks everyone.
Indeed…event dispatcher in BP_GameState and have those that care to be notified of changes bind to that event.
If I had to make an argument for a general “right way” this would be it. You only make updates to the UI when things change AND it’s modular in case you have more than a single entity that cares. Right now you only have one “thing” that cares, as soon as you move to 2 you might as well use events.
Keep in mind that every place you take a shortcut you incur “technical debt”. The moment your project grows, or even that single element of your project grows, you have to go back and redo it. Not ideal. Learning the “right way” up front and just doing it that way all the time will save you headache in the future.