In this lesson, you will learn how to structure C++ ViewModel classes to serve as a clean, decoupled bridge between your game’s raw data and your UMG widgets.
Decoupling Logic from Visuals
In the Model-View-ViewModel (MVVM) pattern, the Model represents your game data (like player health or inventory items), and the View is your UMG Widget. The ViewModel acts as the intermediary. Instead of a widget directly polling the PlayerCharacter every frame—which creates tight coupling and performance overhead—the ViewModel tracks state changes and exposes clean properties that the View can consume.
Creating the ViewModel Class
To create a ViewModel, you define a class derived from UMVVMViewModelBase. This base class provides the necessary infrastructure for property change notifications, allowing UMG to update automatically when your data shifts.
UCLASS()
class UPlayerStatsViewModel : public UMVVMViewModelBase
{
GENERATED_BODY()
public:
// Expose this property to the UMG Designer
UPROPERTY(BlueprintReadWrite, FieldNotify, Setter = SetHealth)
float Health;
void SetHealth(float NewHealth)
{
if (Health != NewHealth)
{
UE_MVVM_SET_PROPERTY_VALUE(Health, NewHealth);
}
}
};
Why Use FieldNotify?
The FieldNotify specifier is critical. When you use the UE_MVVM_SET_PROPERTY_VALUE macro inside a setter, Unreal automatically broadcasts a notification that the property has changed. Because the UMG widget is bound to this ViewModel property, it receives this signal and updates the visual element (like a progress bar or text block) immediately.
This approach ensures that your UI is strictly "data-driven." If you need to change how health is calculated or formatted, you only modify the ViewModel logic; your UI widget remains untouched. By centralizing the formatting and state transformation logic here, you keep your UMG graph clean and prevent the "spaghetti" logic often found in UI Blueprints.
Key Takeaway: ViewModels transform complex game data into a UI-ready format, using FieldNotify properties to ensure your widgets stay in sync with the game state without the need for constant, expensive polling.