UE의 MVVM 플러그인은 UMG UI와 게임플레이 데이터를 직접 연결하지 않고, 중간에 ViewModel을 두어 UI 갱신을 관리하는 구조.

구분 역할
Model 실제 게임 데이터
View UMG Widget
ViewModel Model 데이터를 UI용 값으로 가공하고 변경 알림을 보내는 중간 계층
flowchart LR
    A[Model<br/>게임 데이터] --> B[ViewModel<br/>UI용 데이터]
    B --> C[View<br/>UMG Widget]
    C --> D[화면 표시]

기존 UMG Binding과의 차이

UMG의 Property Binding은 매 프레임 또는 자주 평가되는 방식으로 사용되기 쉬워 성능과 추적성 문제가 생길 수 있다.

MVVM View Binding값이 변경될 때만 바인딩된 위젯에 업데이트를 보내는 이벤트 기반 구조에 가깝다. ViewModel은 변수를 업데이트할 때 관련 위젯만 업데이트하므로
원시 Attribute Binding보다 효율적인 역할을 한다

구분 기존 UMG Binding MVVM View Binding
기준 위젯이 값을 가져오는 방식
MVVM 기준 ViewModel이 변경 알림을 보냄
갱신 방식 평가 기반이 되기 쉬움
MVVM 갱신 FieldNotify 기반
결합도 Widget이 Model을 직접 알기 쉬움
MVVM 결합도 Widget은 ViewModel만 참조
적합한 용도 간단한 임시 UI
MVVM 적합 인벤토리, 체력, 퀘스트, 설정, 상점 등 상태 기반 UI

ViewModel

ViewModel은 UI에서 사용할 값을 보관하고, 값이 바뀌면 UI에 알림을 보내는 객체

C++에서 UMVVMViewModelBase를 상속함.
INotifyFieldValueChanged를 구현하거나, 이를 기본 구현하는 UMVVMViewModelBase를 확장해서 ViewModel을 만들 수 있다.

UCLASS(BlueprintType)
class PROJECTFT_API UWInventoryViewModel : public UMVVMViewModelBase
{
    GENERATED_BODY()

public:
    UPROPERTY(BlueprintReadWrite, FieldNotify, Setter, Getter, Category = "Inventory")
    int32 CurrentWeight = 0;

    UPROPERTY(BlueprintReadWrite, FieldNotify, Setter, Getter, Category = "Inventory")
    int32 MaxWeight = 20;

    void SetCurrentWeight(int32 InCurrentWeight)
    {
        UE_MVVM_SET_PROPERTY_VALUE(CurrentWeight, InCurrentWeight);

        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetWeightText);
        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetWeightPercent);
    }

    int32 GetCurrentWeight() const
    {
        return CurrentWeight;
    }

    void SetMaxWeight(int32 InMaxWeight)
    {
        UE_MVVM_SET_PROPERTY_VALUE(MaxWeight, InMaxWeight);

        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetWeightText);
        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetWeightPercent);
    }

    int32 GetMaxWeight() const
    {
        return MaxWeight;
    }

    UFUNCTION(BlueprintPure, FieldNotify, Category = "Inventory")
    FText GetWeightText() const
    {
        return FText::FromString(
            FString::Printf(TEXT("%d / %d kg"), CurrentWeight, MaxWeight)
        );
    }

    UFUNCTION(BlueprintPure, FieldNotify, Category = "Inventory")
    float GetWeightPercent() const
    {
        return MaxWeight > 0 ? static_cast<float>(CurrentWeight) / MaxWeight : 0.0f;
    }
};
요소 설명
UMVVMViewModelBase UE MVVM용 ViewModel 기반 클래스
FieldNotify 값 변경을 View Binding에 알릴 수 있게 하는 지정자
Setter / Getter ViewModel 외부에서 값을 읽고 쓸 수 있게 하는 접근 지정
UE_MVVM_SET_PROPERTY_VALUE 값이 실제로 바뀐 경우에만 할당 및 알림 처리
UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED 계산형 FieldNotify 함수의 변경을 수동으로 알림

C++에서는 FieldNotify 브로드캐스트를 수동으로 호출해야 한다. 또한 FieldNotify가 없는 변수는 One Time 모드에서만 바인딩할 수 있다.


FieldNotify

FieldNotify가 붙은 변수나 함수는 View Binding 대상이 될 수 있고, 값이 바뀌었을 때 UI에 업데이트를 알릴 수 있다.

UPROPERTY(BlueprintReadWrite, FieldNotify, Setter, Getter)
int32 ItemCount = 0;

FieldNotify 함수

UFUNCTION(BlueprintPure, FieldNotify)
FText GetItemCountText() const
{
    return FText::FromString(FString::Printf(TEXT("x%d"), ItemCount));
}

FieldNotify 함수는 Pure, Const, 단일 반환값, 입력 변수 없음 조건을 만족해야 한다.

FieldNotify 대상 용도
변수 실제 UI 상태값 저장
함수 표시용 텍스트, 퍼센트, Visibility 등 계산값 반환

예를 들어 CurrentHealth가 바뀌면 HealthPercent, HealthText, HealthColor도 같이 바뀌어야 할 수 있다.

void UWHealthViewModel::SetCurrentHealth(float InHealth)
{
    if (UE_MVVM_SET_PROPERTY_VALUE(CurrentHealth, InHealth))
    {
        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetHealthPercent);
        UE_MVVM_BROADCAST_FIELD_VALUE_CHANGED(GetHealthText);
    }
}

View Binding

Widget의 속성과 ViewModel의 필드를 연결

Widget 속성 ViewModel Field
WeightTextBlock.Text GetWeightText()
WeightProgressBar.Percent GetWeightPercent()
ItemNameText.Text ItemName
ItemIcon.Image ItemIconBrush
WarningPanel.Visibility GetWarningVisibility()

UMG 에디터에서는 Widget Blueprint에 ViewModel을 추가한 뒤, View Binding 창에서 위젯 속성과 ViewModel 변수를 연결한다.

방향 의미 예시
One Time to Widget 처음 한 번만 ViewModel 값을 Widget에 반영 초기 제목, 고정 라벨
One Way to Widget ViewModel 변경 시 Widget 갱신 체력바, 무게, 아이템 수량
One Way to ViewModel Widget 입력값을 ViewModel로 전달 텍스트 입력, 설정 값
Two Way 양방향 반영 옵션 UI, 슬라이더 설정

View Binding 방향은 Widget과 ViewModel 사이에서 정보가 흐르는 방식을 결정한다.


ViewModel 생성 방식

Widget에 ViewModel을 붙일 때는 생성 방식을 선택할 수 있다.

생성 방식 설명 사용 예시
Create Instance 위젯이 ViewModel 인스턴스를 자동 생성 독립적인 팝업, 단일 위젯
Manual 외부에서 ViewModel을 생성하고 위젯에 직접 할당 인벤토리, 캐릭터 상태 UI
Global Viewmodel Collection MVVM Game Subsystem의 전역 ViewModel 사용 그래픽 옵션, 계정 정보, 공통 설정
Property Path 위젯 기준 경로를 따라 ViewModel을 찾음 PlayerController, Vehicle, Character가 가진 ViewModel 참조

구현 시 주의점

MVVM을 쓸 때 가장 자주 발생하는 문제는 “값은 바뀌었는데 UI가 안 바뀌는 상황”이다.

문제 원인
UI가 갱신되지 않음 FieldNotify 누락
C++에서 값 변경 후 UI 미갱신 Broadcast 호출 누락
바인딩 목록에 변수가 안 보임 BlueprintReadWrite, FieldNotify, Getter/Setter 접근 문제
함수가 바인딩 목록에 안 보임 Pure, Const, 단일 반환, 입력 없음 조건 불만족
ProgressBar 값 이상 Percent는 보통 0.0 ~ 1.0이어야 함
ViewModel이 Null 생성 방식이 Manual인데 할당하지 않음
여러 위젯 값이 따로 움직임 Create Instance로 각각 다른 ViewModel을 생성함
배열 UI 갱신 안 됨 슬롯 단위 ViewModel 또는 ListView 갱신 구조 부족
반응형

'Unreal Engine' 카테고리의 다른 글

UE 애니메이션 리타게팅  (0) 2026.07.03
언리얼 모듈, Build.cs, 리플렉션  (0) 2026.07.02
Asset Manager + PrimaryAsset  (0) 2026.06.30
언리얼 레퍼런스  (0) 2026.06.29
DataTable, DataAsset  (0) 2026.06.26