Zoeken…


Model View Controller (MVC) ontwerppatroon

De modelweergavecontroller is een veel voorkomend ontwerppatroon dat al geruime tijd bestaat. Dit patroon is gericht op het verminderen van spaghetti- code door klassen in functionele delen te scheiden. Onlangs heb ik met dit ontwerppatroon in Unity geëxperimenteerd en wil ik een eenvoudig voorbeeld geven.

Een MVC-ontwerp bestaat uit drie kernonderdelen: Model, View en Controller.


Model: het model is een klasse die het gegevensgedeelte van uw object vertegenwoordigt. Dit kan een speler, inventaris of een heel niveau zijn. Als dit correct is geprogrammeerd, zou je dit script moeten kunnen nemen en het buiten Unity kunnen gebruiken.

Let op een paar dingen over het model:

  • Het mag niet erven van Monobehaviour
  • Het mag geen Unity-specifieke code voor draagbaarheid bevatten
  • Omdat we Unity API-aanroepen vermijden, kan dit dingen zoals impliciete converters in de klasse Class belemmeren (tijdelijke oplossingen zijn vereist)

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

Een aangepaste Vector3-klasse om te gebruiken met ons gegevensmodel.

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

Weergave: de weergave is een klasse die het kijkgedeelte weergeeft dat aan het model is gekoppeld. Dit is een geschikte klasse om af te leiden uit Monobehaviour. Dit moet code bevatten die rechtstreeks interageert met Unity-specifieke API's, waaronder OnCollisinEnter , Start , Update , enz ...

  • Erft meestal van Monobehaviour
  • Bevat Unity-specifieke code

PlayerView.cs

using UnityEngine;

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

Controller: de controller is een klasse die zowel het model als de weergave verbindt. Controllers houden zowel Model als View synchroon en stimuleren de interactie. De controller kan gebeurtenissen van beide partners beluisteren en dienovereenkomstig updaten.

  • Bindt zowel het model als de weergave door de status te synchroniseren
  • Kan interactie tussen partners stimuleren
  • Controllers kunnen wel of niet draagbaar zijn (mogelijk moet u hier Unity-code gebruiken)
  • Als u besluit om uw controller niet draagbaar te maken, overweeg dan om het een Monobehaviour te maken om te helpen met het inspecteren van de 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;
    }
}

Laatste gebruik

Nu we alle hoofdonderdelen hebben, kunnen we een fabriek maken die alle drie de onderdelen zal genereren.

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

En eindelijk kunnen we de fabriek bellen vanuit een manager ...

Manager.cs

using UnityEngine;

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

Koppel het Manager-script aan een lege GameObject in de scène, klik met de rechtermuisknop op de component en selecteer "Speler laden".

Voor complexere logica kunt u overerving introduceren met abstracte basisklassen en interfaces voor een verbeterde architectuur.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow