Buscar..


Modelo de diseño del controlador de vista (MVC)

El controlador de vista de modelo es un patrón de diseño muy común que ha existido durante bastante tiempo. Este patrón se enfoca en reducir el código de espagueti al separar las clases en partes funcionales. Recientemente he estado experimentando con este patrón de diseño en Unity y me gustaría presentar un ejemplo básico.

Un diseño de MVC consta de tres partes principales: Modelo, Vista y Controlador.


Modelo: el modelo es una clase que representa la porción de datos de su objeto. Esto podría ser un jugador, un inventario o un nivel entero. Si está programado correctamente, debería poder tomar este script y usarlo fuera de Unity.

Tenga en cuenta algunas cosas sobre el modelo:

  • No debe heredar de Monobehaviour.
  • No debe contener código específico de Unity para la portabilidad.
  • Ya que estamos evitando las llamadas a la API de Unity, esto puede dificultar cosas como los convertidores implícitos en la clase Modelo (se requieren soluciones)

Jugador.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

Una clase personalizada de Vector3 para usar con nuestro modelo de datos.

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;
    }
}

Vista: la vista es una clase que representa la parte de visualización vinculada al modelo. Esta es una clase apropiada para derivar de Monobehaviour. Este debe contener código que interactúe directamente con las API específicas de Unity, como OnCollisinEnter , Start , Update , etc.

  • Típicamente hereda de Monobehaviour
  • Contiene código específico de Unity

PlayerView.cs

using UnityEngine;

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

Controlador: el controlador es una clase que une el modelo y la vista. Los controladores mantienen sincronizados tanto el modelo como la vista, así como la interacción de la unidad. El controlador puede escuchar eventos de cualquiera de los socios y actualizarse en consecuencia.

  • Enlaza tanto el modelo como la vista mediante el estado de sincronización
  • Puede impulsar la interacción entre socios
  • Los controladores pueden o no ser portátiles (es posible que tenga que usar el código de Unity aquí)
  • Si decide no hacer que su controlador sea portátil, considere convertirlo en un Monobehaviour para ayudar con la inspección del editor

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;
    }
}

Uso final

Ahora que tenemos todas las piezas principales, podemos crear una fábrica que generará las tres partes.

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);
    }
}

Y finalmente podemos llamar a la fábrica de un gerente ...

Manager.cs

using UnityEngine;

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

Adjunte la secuencia de comandos de Manager a un GameObject vacío en la escena, haga clic con el botón derecho en el componente y seleccione "Cargar jugador".

Para una lógica más compleja, puede introducir la herencia con clases base abstractas e interfaces para una arquitectura mejorada.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow