사용자의 체력, 스탯등 게임 데이터가 UI를 통해 화면상에도 표시되는 경우는 굉장히 흔합니다.
이렇게 게임 데이터 - UI의 관계를 연결하는 방법 중에 직접 연결해주는 방법도 있지만,
추후 확장성과 유지보수 등을 위한 디자인 패턴이 있습니다.
대표적으로 MVC, MVP, MVVM 패턴들이 존재합니다.
⭐ MVC(Model-View-Controller) 패턴
MVC 패턴은 데이터를 담는 Model, 화면에 보여주는 View, 둘을 관리하는 Controller로 이루어진 패턴입니다.
데이터와 뷰를 분리한 패턴 중 가장 초기 패턴으로
데이터와 UI를 분리해 확장성 및 유지보수에 적합한 패턴입니다.
View와 Controller가 서로 참조하여 양방향 관계가 될 수도 있습니다.
● Model
○ 데이터와 로직을 담당합니다.
○ 데이터의 상태를 관리하고 데이터의 변경을 알리는 역할을 수행합니다.
○ ex) 플레이어 체력, 경험치, 점수 등의 데이터 수치를 관리
● View
○ UI(사용자 인터페이스)를 담당합니다.
○ Model에서 변경된 데이터 수치를 시각적으로 나타냅니다.
○ ex) 플레이어의 체력바, 스태미너 등을 표현
● Controller
○ 입력 및 로직 연결을 담당합니다.
○ 사용자의 입력을 받아 Model과 View에 전해주는 역할을 수행합니다.
○ ex) 키 입력이나 버튼 클릭을 통한 Model과 View를 조작
MVC 패턴 예제
아래와 같은 기능을 간단하게 구현해보는 예제입니다.
스페이스키 입력 → 점프, 점프 카운트 UI 증가
A키 입력 → 체력 회복, 체력 UI 증가
D키 입력 → 대미지 입음, 체력 UI 감소
● Model
using System;
using UnityEngine;
public class Player_Model : MonoBehaviour
{
//컴포넌트
[SerializeField] private Rigidbody playerRigid;
//체력
private int currentHp = 100;
public int CurrentHp
{
get { return currentHp; }
set
{
if (value < 0)
value = 0;
currentHp = value;
}
}
public event Action<int> onHealthChanged;
//점프
[SerializeField] private float jumpForce = 10f;
public int JumpCount { get; private set; } = 0;
public event Action<int> onJump;
public void Jump()
{
JumpCount++;
playerRigid.AddForce(jumpForce * Vector3.up, ForceMode.Impulse);
onJump?.Invoke(JumpCount);
}
//amount만큼 대미지가 차거나 줄어듬
public void UpdateHp(int amount)
{
CurrentHp += amount;
onHealthChanged?.Invoke(CurrentHp);
}
}
● 체력과, 점프 횟수 필드를 가지고 있으며, 점프, HP 변경 로직을 갖는 메서드가 있습니다.
● 플레이어와 관련된 데이터 및 로직을 수행하는 메서드를 가지고 있습니다.
● 점프를 하거나, 체력이 변경되었을 때 외부에 알려줄 델리게이트가 있습니다.
● View
using TMPro;
using UnityEngine;
public class Player_View : MonoBehaviour
{
[SerializeField] private TMP_Text text_Hp;
[SerializeField] private TMP_Text text_JumpCount;
public void UpdateHpUI(int currentHp)
{
text_Hp.text = $"Hp: {currentHp}";
}
public void UpdateJumpCountUI(int jumpCount)
{
text_JumpCount.text = $"JumpCount: {jumpCount}";
}
}
● 체력 텍스트, 점프 횟수 텍스트 변경 로직을 갖고 있습니다.
● UI 변경 관련 로직만을 가지고 있습니다.
● Controller
using UnityEngine;
using UnityEngine.InputSystem;
public class Player_Controller : MonoBehaviour
{
[SerializeField] private Player_Model playerModel;
[SerializeField] private Player_View playerView;
private InputAction damageAction; //체력이 깎이는 인풋액션
private InputAction healAction; //체력이 차는 인풋액션
private InputAction jumpAction; //점프하는 인풋액션
private void Awake()
{
damageAction = InputSystem.actions["Damage"];
healAction = InputSystem.actions["Heal"];
jumpAction = InputSystem.actions["Jump"];
}
private void Start()
{
playerModel.onHealthChanged += playerView.UpdateHpUI;
playerModel.onJump += playerView.UpdateJumpCountUI;
}
private void TakeDamage(InputAction.CallbackContext context)
{
playerModel.UpdateHp(-10);
}
private void Heal(InputAction.CallbackContext context)
{
playerModel.UpdateHp(10);
}
private void Jump(InputAction.CallbackContext context)
{
playerModel.Jump();
}
private void OnEnable()
{
damageAction.performed += TakeDamage;
healAction.performed += Heal;
jumpAction.performed += Jump;
}
private void OnDisable()
{
damageAction.performed -= TakeDamage;
healAction.performed -= Heal;
jumpAction.performed -= Jump;
}
}
● Player_Model과 Player_View를 가지고 있습니다.
● 키 입력을 받으면 그에 맞는 메서드를 Player_Model에 접근해 호출합니다.
● Player_View의 UI 변경 메서드를 Player_Model의 델리게이트에 구독합니다.
⭐ MVP(Model-View-Presenter) 패턴
MVC에서 발전한 구조로 View와 비즈니스 로직을 더 깔끔하게 분리할 수 있습니다.
Model, View, Presenter로 구성되어 있으며, 유니티에서 가장 적합하고 자주 쓰이는 방식입니다.
View와 Model은 각각 Presenter에만 의존하므로 단방향 흐름이 생기며 코드 구조가 단순화되는 이점이 있습니다.
● Model
○ 데이터와 그 데이터를 다루는 로직을 갖고 있습니다.
● View
○ UI와 사용자 입력 이벤트를 받습니다.
● Presenter
○ Model과 View를 연결하고, View의 UI 업데이트를 직접 제어합니다.
○ View에서 입력 이벤트를 받으면 Model을 업데이트하고, 그 결과를 다시 View로 전달해 화면을 업데이트합니다.
MVP 패턴 예제
점수가 오를 때 텍스트의 점수도 오르는 매우 간단한 예제입니다.
● Model
using System;
using UnityEngine;
public class MVP_Model : MonoBehaviour
{
public int Score { get; private set; }
public event Action<int> scoreChanged;
public void AddScore()
{
Score++;
scoreChanged?.Invoke(Score);
}
}
● 점수 데이터 프로퍼티와 점수가 오를 때 호출할 델리게이트, 점수를 올리는 메서드로 구성되어 있습니다.
● View
using TMPro;
using UnityEngine;
public class MVP_View : MonoBehaviour
{
[SerializeField] private TMP_Text textScore;
public void UpdateScoreText(int score)
{
textScore.text = $"Score: {score}";
}
}
● TMP_Text의 text 내용을 바꾸는 로직만 담당합니다.
● Presenter
using UnityEngine;
public class MVP_Presenter : MonoBehaviour
{
private MVP_Model model;
private MVP_View view;
public MVP_Presenter(MVP_Model model, MVP_View view)
{
this.model = model;
this.view = view;
}
private void Start()
{
model.scoreChanged += view.UpdateScoreText;
}
public void OnAddScoreButtonClicked()
{
model.AddScore();
}
}
● Model과 View를 받아와 둘을 연결만 해줍니다.
⭐ MVVM(Model-View-ViewModel) 패턴
데이터를 담는 Model, 화면에 보여줄 View, 데이터 바인딩을 이용해
View와 값을 동기화하는 ViewModel로 이루어져 있습니다.
MVP에서는 Presenter에서 직접 View를 업데이트 한다면
MVVM은 ViewModel이 상태를 갖고 있고, View가 그 상태를 자동으로 반영합니다.
● Model
○ 비즈니스, 데이터 로직을 담당하며, UI와 직접적인 관계를 맺지 않습니다.
● View
○ UI를 담당합니다. ViewModel을 통해 필요한 데이터를 표시합니다.
● ViewModel
○ Model과 View의 중개자 역할을 하며, UI 로직을 포함합니다.
○ View에서 발생한 이벤트를 Model에 전달하고, View에 필요한 데이터를 제공합니다.
○ View와 ViewModel간의 데이터 바인딩을 통해 변화를 자동으로 감지합니다.
MVVM 패턴 예제
● Model
using UnityEngine;
public class MVVM_Model : MonoBehaviour
{
public int Score { get; private set; }
public void AddScore()
{
Score++;
}
}
● View
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class MVVM_View : MonoBehaviour
{
[SerializeField] private TMP_Text textScore;
[SerializeField] private Button addButton;
private MVVM_ViewModel viewModel;
public void BindingData(MVVM_ViewModel viewModel)
{
this.viewModel = viewModel;
//등록
viewModel.onScoredChanged += value => textScore.text = $"Score: {value}";
//UI입력 → ViewModel 호출
addButton.onClick.AddListener(() => this.viewModel.AddScore());
//초기화
textScore.text = $"Score: {this.viewModel.GetScore()}";
}
}
● ViewModel
using System;
using UnityEngine;
public class MVVM_ViewModel : MonoBehaviour
{
private MVVM_Model model;
public event Action<int> onScoredChanged;
public MVVM_ViewModel(MVVM_Model model)
{
this.model = model;
}
public void AddScore()
{
model.AddScore();
onScoredChanged?.Invoke(model.Score);
}
public int GetScore()
{
return model.Score;
}
}'개발, IT > 디자인 패턴 & 알고리즘' 카테고리의 다른 글
| [알고리즘] 다익스트라 알고리즘 (Dijkstra Algorithm) (0) | 2025.11.20 |
|---|---|
| [디자인 패턴] FSM (Finite-State Machine) 유한 상태 기계 (0) | 2025.11.12 |
| [디자인 패턴] 옵저버 패턴 (Observer Pattern) (0) | 2025.10.22 |
| [디자인 패턴] 어댑터 패턴 (Adapter Pattern) (0) | 2025.10.21 |
| [디자인 패턴] Object Pooling (오브젝트 풀링) (0) | 2025.09.30 |