안녕하세요

프로그램 과정에서 막혔던 문제들에 대한 해결책 정리


페이지 목록

레이블이 MVC인 게시물을 표시합니다. 모든 게시물 표시
레이블이 MVC인 게시물을 표시합니다. 모든 게시물 표시

2025년 11월 26일 수요일

[유니티][Unity] MVC와 MVP 소프트웨어 디자인 패턴 및 MVP가 유니티개발에 유리한 이유

 사용자 인터페이스(UI)를 구성할 때 사용되는 아키텍쳐 패턴으로 소프트웨어 디자인패턴이다.
 세가지 핵심 역할로 분리해서 애플리케이션의 로직을 만드는데 이렇게 함으로써 코드의 유지 보수성과 확장성을 높이게 된다.
 
 UI 패턴 또는 애플리케이션 설계 패턴으로 불린다.

 1. MVC ( Model-View-Controller) 모델
  
    Model (모델): 비즈니스 로직과 데이터를 관리함
    View(뷰) : UI(화면)을 담당
    Controller(컨트롤러): Model이나 View를 업데이트하는 사용자의 입력(마우스 클릭,키보드 입력)을 받음

 2. MVP (Model-View-Presenter) 모델
   MVC에서 파생된 패턴으로 Unity와 같은 환경에서 더 선호하는 경향이 있다.
 
  Model(모델) : 비즈니스 로직과 데이터 관리 (1번 모델과 동일)
  View (뷰) : 화면(UI)를 담당하여 사용자에게 보여지는 부분이다, Presenter에 사용자 입력을 전달, 자체 로직은 거의 없음
  Presenter (프리젠터): 중개자 역할을 함 (View와 Model 사이), View에게 받은 입력으로 Model을 업데이트하고, Model의 변경사항을 감지하여 View를 업데이트 하도록 지시함, View와 Model을 강력하게 연결함

 MVP를 선호하는 이유
 유니티의 컴포넌트 기반 아키텍쳐(Component-based Architecture)와의 테스트 용이성 및 호환성이 좋기 때문이다.

 MVP는 MVC에서 파생되었지만 유니티 환경에서 몇 가지 핵심적인 차이가 있고 이 부분에서 MVP가 장점을 가진다.

 1.View와 Presenter 간의 명확한 분리 (느슨한 결합)

    MVC의 Cotroller: Controller와 View가 강하게 결합되는 경향이 있음 Cotroller가 입력을 처리하고 View를 직접 업데이트 할 수 있음

    MVP의 Presenter: Presenter는 중개자 역할을 함 (View와 Model 사이), View는 Presenter의 지시를 따르기만 함. View가 수동적인 역할을 하게 되고 자체 로직이 최소화 됨

    유니티에서의 장점: 유니티의 MonoBehaviour 스크립트는 필연적으로 Transform,Animator, GameObject 등 유니티 엔진 요소에 종속됨. 
    MVP에서는 이런 종속적인 코드를 View에 집중시키고, 제어 흐름과 핵심 게임로직을 담당하는 Presenter는 유니티 의존성을 줄일 수 있게 됨

2. 테스트 용이성 (Testability)
 테스트는 유니티 개발에서 중요한 이슈임
  
 MVP의 Presenter및 Model: 순수 C# 클래스(Plain C# Objects)로 MonoBehaviour를 상속받지 않을 수 있음. 이렇게 되면 유니티 엔진 없이 단위 테스트(Unit Test) 프레임 워크를 사용하여 쉽게 테스트가 가능함
 
 MVC의 Controller/View: 유니티 컴포넌트에 강하게 의존하는 경우, 전체 유니티 씬과 엔진 환경을 구동해야 테스트가 되어 테스트가 복잡하고 느려짐

 유니티에서의 장점: 유니티와 독립적으로 빠르게 테스트 가능 (핵심 게임로직(체력 계산, 사망 판정 등))

 3. 유니티 컴포넌트 시스템과의 조화
 
 MVP 구조: Presenter는 메인 Gameobject(예:보스)에 부착하고, View는 UI Canvas에 부착하는 등 유니티의 컴포넌트 기반 아키텍처에 자연스러운 매핑이 가능함

 MVC 구조: 전통적인 MVC 구조는 UI 프레임워크(예: 웹, 모바일)에 더 적합하게 설계되어서 유니티의 GameObject 계층 구조에 완벽하게 맞지 않을 수가 있음
 

 구글 AI의 도움을 받아 작성되었습니다.

2024년 12월 27일 금요일

[유니티][Unity][chatGPT] Unity2D에서 MVC로 구현한 보스가 주인공 위치에 원형의 범위기술을 사용 후 Duration시간 뒤에 터지는 기술

 Unity 2D에서 MVC(Model-View-Controller) 패턴으로 보스가 주인공 위치를 기준으로 원형 범위 공격을 수행하는 시스템을 설계하는 코드이다. MVC 패턴은 코드의 분리를 통해 가독성과 유지보수성을 높이는 것을 목표로 한다.



MVC 구조

  1. Model:

    • 데이터 및 로직을 처리합니다.
    • 스킬 반경, 경고 시간, 데미지 값 등을 관리.
  2. View:

    • 사용자에게 보여지는 경고 UI와 스킬 효과를 처리합니다.
    • 경고 UI 생성, 스킬 효과 표시 등을 담당.
  3. Controller:

    • 사용자 입력이나 로직의 흐름을 관리합니다.
    • 보스의 행동을 제어하고 Model과 View를 연결.

1. SkillModel (Model)

스킬 데이터를 관리하고 범위 내 타겟을 감지하는 로직을 구현합니다.

csharp
using UnityEngine; public class BossSkillModel { public float Radius { get; private set; } public float Damage { get; private set; } public float WarningDuration { get; private set; } public BossSkillModel(float radius, float damage, float warningDuration) { Radius = radius; Damage = damage; WarningDuration = warningDuration; } // 범위 내 타겟 감지 public Collider2D[] GetTargets(Vector2 position, LayerMask targetLayer) { return Physics2D.OverlapCircleAll(position, Radius, targetLayer); } }

2. SkillView (View)

스킬의 시각적 요소를 관리합니다.

 - 경고 UI 프리팹에 임의로 그림판으로 작성한 원을 넣어 주고, 스킬 효과 프리팹은 아직 작성하지 않았다. (스킬 효과 프리팹은 주석 처리해도 동작한다)

csharp
using UnityEngine; public class BossSkillView : MonoBehaviour { public GameObject WarningPrefab; // 경고 UI 프리팹 public GameObject EffectPrefab; // 스킬 효과 프리팹 private GameObject warningInstance; // 경고 UI 표시 public void ShowWarning(Vector2 position, float radius) { warningInstance = Instantiate(WarningPrefab, position, Quaternion.identity); warningInstance.transform.localScale = new Vector3(radius * 2, radius * 2, 1); } // 경고 UI 제거 public void HideWarning() { if (warningInstance != null) { Destroy(warningInstance); } } // 스킬 효과 표시 public void ShowSkillEffect(Vector2 position, float radius) { GameObject effect = Instantiate(EffectPrefab, position, Quaternion.identity); effect.transform.localScale = new Vector3(radius * 2, radius * 2, 1); } }

3. BossController (Controller)

보스의 행동을 관리하고 Model과 View를 연결합니다.

 - BossSkillController가 아니라 BossController인 이유는 보스가 사용하는 스킬이기 때문이고, 작은 프로젝트의 경우 BossSkillController를 따로 구분 하지 않고 하나의 BossController에서 사용해도 감당 가능하기에 BossController를 사용한다. 

   감당이 안된다면 BossSkillController를 별도로 만들어 사용해도 된다.

csharp
using UnityEngine; public class BossController : MonoBehaviour { public Transform player; // 주인공 Transform public LayerMask targetLayer; // 타겟 레이어 public SkillView skillView; // 스킬 View private SkillModel skillModel; // 스킬 데이터 void Start() { // Model 초기화 skillModel = new SkillModel(radius: 5.0f, damage: 50.0f, warningDuration: 2.0f); } public void StartSkill() { if (player == null) { Debug.LogError("Player가 설정되지 않았습니다!"); return; } // 주인공 위치 저장 Vector2 targetPosition = player.position; // View를 통해 경고 UI 표시 skillView.ShowWarning(targetPosition, skillModel.Radius); // 일정 시간 후 스킬 발동
StartCoroutine(ActivateSkillAfterDelay(targetPosition, bossSkillModel.WarningDuration)); }

    IEnumerator ActivateSkillAfterDelay(Vector2 targetPosition, float delay)     {     yield return new WaitForSeconds(delay);      ActivateSkill(targetPosition);     } private void ActivateSkill(Vector2 targetPosition) { // View에서 경고 UI 제거 skillView.HideWarning(); // View에서 스킬 효과 표시 skillView.ShowSkillEffect(targetPosition, skillModel.Radius); // Model을 통해 범위 내 타겟 감지 Collider2D[] hitTargets = skillModel.GetTargets(targetPosition, targetLayer); foreach (var target in hitTargets) { target.GetComponent<Health>()?.TakeDamage(skillModel.Damage); } Debug.Log("스킬 발동 완료!"); } }

4. Health (Model)

주인공이나 다른 타겟이 데미지를 받을 수 있도록 체력을 관리합니다.

csharp
using UnityEngine; public class Health : MonoBehaviour { public float MaxHealth = 100f; private float currentHealth; void Start() { currentHealth = MaxHealth; } public void TakeDamage(float amount) { currentHealth -= amount; Debug.Log($"{gameObject.name} 남은 체력: {currentHealth}"); if (currentHealth <= 0) { Die(); } } private void Die() { Debug.Log($"{gameObject.name} 사망"); Destroy(gameObject); } }

5. Unity 설정

1) 보스 설정

  1. Boss GameObject에 **BossController**와 SkillView 스크립트를 추가.
  2. SkillView 설정:
    • WarningPrefabEffectPrefab을 연결.
  3. BossController 설정:
    • 주인공의 Transform을 Player 필드에 연결.
    • TargetLayer에 적합한 레이어 설정(예: "Player").

2) 주인공 설정

  1. 주인공 GameObject에 Health 스크립트 추가.
  2. Inspector에서 MaxHealth 값 설정.

3) 경고 및 공격 효과 프리팹

  • WarningPrefab: 원형 이미지 기반 UI.
  • EffectPrefab: 원형 스프라이트 또는 파티클 효과.

6. 테스트

  1. BossControllerStartSkill 메서드를 호출(키 입력으로 테스트 가능).
    csharp
    void Update() { if (Input.GetKeyDown(KeyCode.F)) { StartSkill(); } }
  2. 주인공 이동:
    • 스킬 발동 위치와 데미지 처리가 주인공의 위치에 맞게 동작하는지 확인.

결과

  • 보스는 주인공의 위치를 감지하여 원형 범위 경고를 표시하고, 일정 시간 후 해당 위치에서 스킬을 발동한다.
  • 범위 내에 있는 대상(주인공 포함)은 데미지를 받는다.

MVC 패턴 장점

  1. 코드 분리:

    • 데이터(Model), 시각적 요소(View), 로직(Control)이 독립적으로 관리되므로 유지보수성 향상.
  2. 확장성:

    • 새로운 스킬 View 또는 Model을 쉽게 추가 가능.
  3. 테스트 용이성:

    • 각 컴포넌트를 독립적으로 테스트 가능.

** 이 글은 chatGPT의 도움으로 작성되었습니다.