Suche…


Muster für Modellansicht-Controller (MVC)

Der Model-View-Controller ist ein sehr verbreitetes Designmuster, das es schon seit einiger Zeit gibt. Dieses Muster konzentriert sich auf die Reduzierung von Spaghetti- Code, indem Klassen in Funktionsteile unterteilt werden. Ich habe kürzlich mit diesem Entwurfsmuster in Unity experimentiert und möchte ein grundlegendes Beispiel darstellen.

Ein MVC-Design besteht aus drei Kernteilen: Modell, Ansicht und Controller.


Modell: Das Modell ist eine Klasse, die den Datenteil Ihres Objekts darstellt. Dies kann ein Spieler, Inventar oder ein ganzes Level sein. Bei korrekter Programmierung sollten Sie dieses Skript auch außerhalb von Unity verwenden können.

Beachten Sie ein paar Dinge zum Modell:

  • Es sollte nicht von Monobehaviour erben
  • Es sollte keinen Unity-spezifischen Code für die Portabilität enthalten
  • Da wir Unity-API-Aufrufe vermeiden, kann dies Dinge wie implizite Konverter in der Model-Klasse verhindern (Problemumgehungen sind erforderlich).

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

Eine benutzerdefinierte Vector3-Klasse für unser Datenmodell.

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

Ansicht: Die Ansicht ist eine Klasse, die den mit dem Modell verknüpften Ansichtsteil darstellt. Dies ist eine geeignete Klasse, um von Monobehaviour abgeleitet zu werden. Dieser sollte Code enthalten, der direkt mit Unity-spezifischen APIs wie OnCollisinEnter , Start , Update usw. interagiert.

  • Üblicherweise erbt er von Monobehaviour
  • Enthält Unity-spezifischen Code

PlayerView.cs

using UnityEngine;

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

Controller: Der Controller ist eine Klasse, die Modell und Ansicht miteinander verbindet. Controller halten sowohl Model und View als auch die Interaktion mit dem Laufwerk synchron. Der Controller kann Ereignisse von beiden Partnern überwachen und entsprechend aktualisieren.

  • Bindet sowohl das Modell als auch die Ansicht, indem der Status synchronisiert wird
  • Kann die Interaktion zwischen Partnern fördern
  • Controller sind möglicherweise portabel (möglicherweise müssen Sie hier Unity-Code verwenden)
  • Wenn Sie sich dafür entscheiden, Ihren Controller nicht portabel zu machen, sollten Sie ihn als Monobehaviour in Betracht ziehen

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

Endgültige Verwendung

Nun, da wir alle Hauptteile haben, können wir eine Fabrik schaffen, die alle drei Teile erzeugt.

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

Und schließlich können wir die Fabrik von einem Manager anrufen ...

Manager.cs

using UnityEngine;

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

Hängen Sie das Manager-Skript an ein leeres GameObject in der Szene an, klicken Sie mit der rechten Maustaste auf die Komponente und wählen Sie "Player laden".

Für eine komplexere Logik können Sie Vererbung mit abstrakten Basisklassen und Schnittstellen für eine verbesserte Architektur einführen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow