MVVM & UI
Table of Contents
Overview
PulseQuest provides a set of pre-wired MVVM ViewModels (built on Unreal’s UMVVMViewModelBase) for every layer of the quest hierarchy. You bind these to UMG widgets using the standard MVVM binding system.
ViewModels are created lazily on first access, not during BeginPlay. This avoids overhead when quests/objectives are running headlessly on the server or during automated tests.
ViewModel Hierarchy
UMVVMPulseQuestManager ← one per quest manager
└── UMVVMPulseQuest ← one per active quest
└── UMVVMPulseObjective ← one per active objective
UMVVMPulseQuestManagerData ← wraps UPulseQuestManagerData
UMVVMPulseQuestManager
Attached to UPulseQuestManager or APulseSharedQuestHost. Provides:
| Field | Type | Notify |
|---|---|---|
ActiveQuests | TArray<UMVVMPulseQuest*> | FieldNotify |
ActiveObjectives | TArray<UMVVMPulseObjective*> | FieldNotify |
ManagerData | UMVVMPulseQuestManagerData* | FieldNotify |
Lazy creation
// Called on first access
UMVVMPulseQuestManager* GetQuestManagerViewModel() const;
If no QuestManagerViewModelClass is set in ManagerParams, no ViewModel is created and the getter returns nullptr.
UMVVMPulseQuest
One per active quest; created when the quest starts.
| Field | Type | Notify |
|---|---|---|
QuestTag | FGameplayTag | FieldNotify |
DisplayName | FText | FieldNotify |
Description | FText | FieldNotify |
FinishState | EPulseQuestFinishResult | FieldNotify |
ActiveObjectives | TArray<UMVVMPulseObjective*> | FieldNotify |
bIsStopped | bool | FieldNotify |
Access:
UMVVMPulseQuest* VM = QuestData->GetQuestDataViewModel();
UMVVMPulseObjective
One per active objective (when ViewModelClass is set on the objective).
| Field | Type | Notify |
|---|---|---|
SaveID | FName | FieldNotify |
FinishStatus | EPulseObjectiveCompletionStatus | FieldNotify |
bIsFinished | bool | FieldNotify |
Progress | float (0–1) | FieldNotify |
Access:
UMVVMPulseObjective* VM = Objective->GetObjectiveViewModel();
Subclass UMVVMPulseObjective to add your own fields (e.g. CurrentCount, TargetCount):
UCLASS()
class UMVVMMyKillObjective : public UMVVMPulseObjective
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, FieldNotify)
int32 KillCount = 0;
UPROPERTY(BlueprintReadWrite, FieldNotify)
int32 KillTarget = 10;
};
Then set ViewModelClass = UMVVMMyKillObjective::StaticClass() in the objective’s FPulseQuestObjectiveAddParams.