Looking for unity3d Answers? Try Ask4KnowledgeBase
Looking for unity3d Keywords? Try Ask4Keywords

unity3d 모델 뷰 컨트롤러 (MVC) 디자인 패턴


모델 뷰 컨트롤러는 아주 일반적인 디자인 패턴으로 꽤 오랫동안 사용되어 왔습니다. 이 패턴은 클래스를 기능적 부분으로 분리하여 스파게티 코드를 줄이는 데 중점을 둡니다. 최근 유니티 (Unity)에서이 디자인 패턴을 실험 해본 결과 기본 예제를 설명하고자합니다.

MVC 디자인은 모델, 뷰 및 컨트롤러의 세 가지 핵심 파트로 구성됩니다.


모델 : 모델은 개체의 데이터 부분을 나타내는 클래스입니다. 이것은 플레이어, 재고 또는 전체 레벨 일 수 있습니다. 올바르게 프로그램 되었다면이 스크립트를 가져 와서 Unity 외부에서 사용할 수 있어야합니다.

모델에 대한 몇 가지 사항을 참고하십시오.

  • Monobehaviour에서 상속해서는 안됩니다.
  • 이식성을 위해 Unity 특정 코드를 포함해서는 안됩니다.
  • Unity API 호출을 피하기 때문에 Model 클래스의 암시 적 변환기와 같은 문제가 발생할 수 있습니다 (해결 방법 필요)

Player.cs

using System;

public class Player
{
    public delegate void PositionEvent(Vector3 position);
    public event PositionEvent OnPositionChanged;

    public Vector3 position 
    {
        get 
        {
            return _position;
        }
        set 
        {
            if (_position != value) {
                _position = value;
                if (OnPositionChanged != null) {
                    OnPositionChanged(value);
                }
            }
        }
    }
    private Vector3 _position;
}

Vector3.cs

데이터 모델과 함께 사용할 사용자 정의 Vector3 클래스입니다.

using System;

public class Vector3
{
    public float x;
    public float y;
    public float z;

    public Vector3(float x, float y, float z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

보기 : 보기는 모델에 연결된보기 부분을 나타내는 클래스입니다. 이것은 Monobehaviour에서 파생되는 적절한 클래스입니다. 이것은 OnCollisinEnter , Start , Update 등을 포함한 Unity 특정 API와 직접 상호 작용하는 코드를 포함해야합니다.

  • 일반적으로 Monobehaviour에서 상속받습니다.
  • 유니티 특정 코드 포함

PlayerView.cs

using UnityEngine;

public class PlayerView : Monobehaviour
{
    public void SetPosition(Vector3 position)
    {
        transform.position = position;
    }
}

컨트롤러 : 컨트롤러는 모델과 뷰를 함께 묶는 클래스입니다. 컨트롤러는 모델 상호 작용뿐만 아니라 모델 및 뷰를 동기화 상태로 유지합니다. 컨트롤러는 파트너 중 하나의 이벤트를 수신하고 그에 따라 업데이트 할 수 있습니다.

  • 동기화 상태별로 모델 및보기를 바인딩합니다.
  • 파트너 간의 상호 작용을 유도 할 수 있습니다.
  • 컨트롤러는 이식 가능할 수도 있고 없을 수도 있습니다 (유니티 코드를 사용해야 할 수도 있습니다)
  • 컨트롤러를 휴대용으로 만들지 않으려면 편집자 검사에 도움이되는 Monobehaviour를 사용하는 것이 좋습니다.

PlayerController.cs

using System;

public class PlayerController
{
    public Player model { get; private set; }
    public PlayerView view { get; private set; }

    public PlayerController(Player model, PlayerView view)
    {
        this.model = model;
        this.view = view;

        this.model.OnPositionChanged += OnPositionChanged;
    }

    private void OnPositionChanged(Vector3 position)
    {
        // Sync
        Vector3 pos = this.model.position;

        // Unity call required here! (we lost portability)
        this.view.SetPosition(new UnityEngine.Vector3(pos.x, pos.y, pos.z));
    }
    
    // Calling this will fire the OnPositionChanged event 
    private void SetPosition(Vector3 position)
    {
        this.model.position = position;
    }
}

최종 사용

이제 우리는 모든 주요 부분을 가지고 있으므로 세 부분을 모두 생성하는 팩토리를 만들 수 있습니다.

PlayerFactory.cs

using System;

public class PlayerFactory
{
    public PlayerController controller { get; private set; }
    public Player model { get; private set; }
    public PlayerView view { get; private set; }

    public void Load()
    {
        // Put the Player prefab inside the 'Resources' folder
        // Make sure it has the 'PlayerView' Component attached
        GameObject prefab = Resources.Load<GameObject>("Player");
        GameObject instance = GameObject.Instantiate<GameObject>(prefab);
        this.model = new Player();
        this.view = instance.GetComponent<PlayerView>();
        this.controller = new PlayerController(model, view);
    }
}

그리고 마침내 우리는 매니저로부터 공장으로 전화 할 수 있습니다 ...

Manager.cs

using UnityEngine;

public class Manager : Monobehaviour
{
    [ContextMenu("Load Player")]
    private void LoadPlayer()
    {
        new PlayerFactory().Load();
    }
}

장면의 빈 GameObject에 Manager 스크립트를 연결하고 구성 요소를 마우스 오른쪽 버튼으로 클릭 한 다음 "Load Player"를 선택합니다.

보다 복잡한 로직을 위해 추상적 인 기본 클래스와 인터페이스로 상속을 도입하여 개선 된 아키텍처를 구현할 수 있습니다.