Sök…


Model View Controller (MVC) designmönster

Modellsynskontrollern är ett mycket vanligt designmönster som har funnits länge. Detta mönster fokuserar på att minska spagettikoden genom att dela klasser i funktionella delar. Nyligen har jag experimenterat med detta designmönster i Unity och skulle vilja presentera ett grundläggande exempel.

En MVC-konstruktion består av tre kärndelar: Model, View och Controller.


Modell: Modellen är en klass som representerar datadelen av ditt objekt. Detta kan vara en spelare, inventering eller en hel nivå. Om du har programmerat korrekt bör du kunna ta detta skript och använda det utanför Unity.

Lägg märke till några saker om modellen:

  • Den bör inte ärva från Monobehaviour
  • Den bör inte innehålla enhetsspecifik kod för portabilitet
  • Eftersom vi undviker Unity API-samtal kan detta hindra saker som implicita omvandlare i modellklassen (lösningar krävs)

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

En anpassad Vector3-klass att använda med vår datamodell.

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

Vy: Vyn är en klass som representerar den visningsdel som är bunden till modellen. Detta är en lämplig klass att härleda från Monobehaviour. Detta bör innehålla kod som interagerar direkt med Unity-specifika API: er inklusive OnCollisinEnter , Start , Update , etc. ...

  • Arver vanligtvis från Monobehaviour
  • Innehåller enhetsspecifik kod

PlayerView.cs

using UnityEngine;

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

Controller: Controllern är en klass som binder samman både Model och View. Styrenheter har både modell och vy synkroniserat såväl som enhetens interaktion. Styrenheten kan lyssna på händelser från endera partnern och uppdatera därefter.

  • Binder både modell och vy genom att synkronisera tillstånd
  • Kan driva interaktion mellan partner
  • Styrenheter kan eller inte vara portabla (Du kanske måste använda enhetskod här)
  • Om du bestämmer dig för att inte göra din controller bärbar, kan du överväga att göra det till en Monobehaviour för att hjälpa till med redaktörsinspektionen

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

Slutlig användning

Nu när vi har alla huvudstyckena kan vi skapa en fabrik som kommer att generera alla tre delarna.

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

Och slutligen kan vi ringa fabriken från en chef ...

Manager.cs

using UnityEngine;

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

Bifoga Manager-skriptet till ett tomt GameObject i scenen, högerklicka på komponenten och välj "Load Player".

För mer komplex logik kan du introducera arv med abstrakta basklasser och gränssnitt för en förbättrad arkitektur.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow