I looked around the Forum and can’t really find anything this specific.
I’ve got a variable score that is handled by the Gamestate and can’t figure out how to pass it over to the Player’s HUD while also trying to be performance conscious as this is for Multiplayer. But ALL players need to see the same Gamestate variable.
1 Like
Some options :
-
In GameState, make sure the variable is Replicated with RepNotify. In the blueprint it will automatically create a function OnRep_Score. That function is called whenever variable is updated. From there, get player HUD through GetPlayerController(0) → GetHUD and pass the new value.
-
In GameState, create an event dispatcher like “OnScoreChanged” with a Score parameter. Make sure the variable is Replicated with RepNotify. From the repnotify function (OnRep_Score), trigger the event dispatcher with the value of the Score variable. In your HUD BeginPlay or Widget Construct event, access your game state via GetGameState → Cast To YourGameState and bind the event dispatcher.
-
Create an interface with a function like “UpdateScore” with a Score parameter. In your HUD, implement that interface (and its function). In GameState, make sure the variable is Replicated with RepNotify. From the repnotify function (OnRep_Score) call the interface into player HUD via GetPlayerController(0) → GetHUD → Call UpdateScore (interface call).
-
If this is for a UMG widget, in the text portion of the widget instead of setting a text you can assign a binding. This will create a function which purpose is to return the text to display. From that function, access your game state via GetGameState → Cast To YourGameState and retrieve the Score variable. In GameState make sure the variable is Replicated (no need RepNotify).
Note the following considerations :
-
Option 1 is easy to implement, but creates a hard referencing from your GameState class to your HUD class. It is also event-based which is more optimal.
-
Option 2 creates a hard referencing from your HUD class to your GameState class. It is also event-based.
-
Option 3 creates no hard referencing and is also event based.
-
Option 4 is easiest to implement (for widgets), but is not event-based. These binding functions are called every frame so using many of them will have a performance hit. It also creates a hard referencing from HUD class to GameState class.
-
Also note that hard referencing is not necessarily bad. In case of blueprints it’s better if you can avoid them, but if you have C++ for GameState you could move the event dispatcher there, or if you have C++ for HUD you could have a C++ function UpdateScore there (blueprint-implementable). Then instead of casting to the BP class you only cast to the C++ class which is fine and referencing becomes a non-issue. Alternatively if you already have a reference in one direction (eg. HUD → GameState or GameState → HUD), use that which you already have.
-
Beware of use cases. Option 3 (interface) sounds like best on paper.. but if for example you need to pass the replicated Score to multiple objects, then event dispatcher may be more suited for that job.
4 Likes
I sincerely appreciate your reply! I had done method 4 but forgot to make it Replicated. It’s always something simple.
I’ll try out the other methods since you said #4 causes performance hits. And initially I intended on using this method for 5 different variables. Is that too many across 6~ players?
The number of players does not matter here, each player is running the game on his own machine and only worries about his own widgets. They don’t execute the widget code for other players (unless we are talking about split-screen MP).
If your bindings are simply accessing variables in GameState, or other classes that are easy to reach, you probably shouldn’t have to worry about performance there. Even with 5, 10, or 15 of them. However if a binding has to execute many blueprint nodes to find/calculate calculate whatever it has to display, consider moving to event-based. Some specific nodes are also very expensive such as GetAllActorsWithInterface or GetAllActorsWithTag for example.
2 Likes
I agree with all you said but if in 2. you create an event dispatcher, you could do so as well in 4. Widgets are great using the observer pattern (if event X happens , do Y), which is in all cases better than creating a binding of text X to property Y. A delegate bound setter function to directly set a text on widget X avoids having a dupe text property and is more performant, since the widget doesn’t check for data every frame.
To be more literal, widgets are only created on the client in a networked game.
Hard reference itself is no downside? Everything is loaded in memory already and is expected to remain there.
1 Like
Not sure what you mean here. Option 2 presents the dispatcher approach, while option 4 presents the UMG-binding approach (which executes every frame). What do you mean using option 2 in option 4 ? 
It’s true that hard-referencing is often overemphasized. If you have one game mode, one game state, one HUD throughout your whole game, then yes all of them will always be loaded in memory and it’s not an issue that they are all interdependent. But generally as the game grows in size, you create more stuff that are specific to certain situations/levels, and don’t want them loaded at all times. For example let’s say the Score widget matters in LevelA, but is not used in LevelB, and for some reason you still use the same GameState for both. The simple presence of a CastTo_ScoreWidget node in the GameState’s BP graph is enough to trigger loading of the ScoreWidget asset in memory, even if it is not used at all in LevelB.
2 Likes
I meant using the dispatcher instead of the UMG binding would be more optimal.
When the event itself provides the data for the widget (like the text to display), the widget has no need for checking every frame, and responds instantly.
(used a screenshot of what I could find, my assets are c++ based instead of BP)
https://www.youtube.com/watch?v=ayCEqL7XFZY
This is true.
You might also want to read this now we’re talking about memory usage:
All about Soft and Weak pointers | Tutorial
1 Like