Add the MVP in the game for Unity3D

As we all know with you, MVP - is a template designed to separate presentation logic from application logic. If Unity3D, performance can be GameObject with a set of components attached to it necessary for the implementation of presentation logic (including the components of the presentation logic - MonoBehaviour implementing the appropriate presentation interface (View)).

In the role of presenter (Presenter) can be any type of .NET, implementing certain parts of the application logic and interacting with the other parts of it, such as models, services ...

So, suppose before, our goal is to create a very simple game in which the player represented the most extensive arsenal of possible actions: all he can do - click on the image color of the rectangle. In response to the actions of the player box can jump, roll over and change color at random, according to the logic of the game. This is a very simple example, but it is enough to understand how to apply the MVP pattern in the development of games Unity3D.

Let's look at a possible variant of the organization of the project shown in the following figure:

Pay attention to the script in the list of ingredients FunnyRectView object FunnyRect. This script - realization presentation functionality. Type FunnyRectView implements interface IFunnyRectView, as well as, the interface is actively used by presenter to interact with the presentation.

Here is the code FunnyRectView.

public class FunnyRectView : MonoBehaviour, IFunnyRectView 
{     
    private IFunnyRectPresenter _presenter;
    
    public void Awake()
    {
        _presenter = new FunnyRectPresenter(this);
        _presenter.Initialize();
    }
}

Bunch presentation with presenter occurs in Awake. Presenter, as a constructor parameter takes the type of link IFunnyRectView. This interface and serves as a bridge that connects the performance with the presenter. It allows you to call methods defined in FunnyRectView, subscribe and respond to its events. Presentation also has the ability to interact with the presenter through stored in _presenter link.

Let's add the necessary for normal functioning of the logic in FunnyRectView.

public class FunnyRectView : MonoBehaviour, IFunnyRectView
{
    private IFunnyRectPresenter _presenter;
    private bool _isInputEnabled;
    private Animator _animator;
    private const string JumpAnimationTriggerName = "JumpTrigger";
    private const string RotateAnimationTriggerName = "RotateTrigger";

    public void Awake()
    {
        _presenter = new FunnyRectPresenter(this);
        _animator = gameObject.GetComponent<Animator>();
        _presenter.Initialize();
    }
    public void OnDestroy()
    {
        _presenter.Uninitialize();
    }
    public event EventHandler RotationEnd;
    public event EventHandler JumpEnd;
    public event EventHandler Clicked;
    public void OnMouseDown()
    {
        if (!_isInputEnabled) return;
        Clicked(this, EventArgs.Empty);
    }
    public void NotifyRotationEnded()     
    {
        RotationEnd(this, EventArgs.Empty);
    }
    public void NotifyJumpEnded()     
    {
        JumpEnd(this, EventArgs.Empty);
    }
    public void DisableInput()     
    {
        _isInputEnabled = false;
    }
    public void EnableInput()     
    {
        _isInputEnabled = true;
    }
    public void Rotate()     
    {
        _animator.SetTrigger(RotateAnimationTriggerName);
    }
    public void Jump()
    {
        _animator.SetTrigger(JumpAnimationTriggerName);     
    }
    public void ChangeColor(Color color)     
    {         
        var spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
        spriteRenderer.color = color;
        _isInputEnabled = true;
    }
}

The method Awake, get a reference to the component animator. He needs to jump and play the animation revolution rectangle. Clicked event you need to notify the presenter that the player clicked on the box. This happens OnMousedDown (on the rectangle present Collider). Methods NotifyRotationEnded and NotifyJumpEnded called animator, at the time when the animation ends with a jump or a coup, and generate events and JumpEnd RotationEnd respectively. All other methods are called from the presenter.

public class FunnyRectPresenter : IFunnyRectPresenter
{
    private readonly IFunnyRectView _view;
    private const int FunnyRectRotateActionCode = 0;
    private const int FunnyRectJumpActionCode = 1;
    private const int FunnyRectChangeColorActionCode = 2;
    public FunnyRectPresenter(IFunnyRectView view)
    {         
        _view = view;
    }
    private void OnRectClicked(object sender, EventArgs e)
    {
        _view.DisableInput();
        var action = GenerateRandomAction();
        switch (action)
        {
            case FunnyRectRotateActionCode:
                _view.Rotate();
                break;
            case FunnyRectJumpActionCode:
                _view.Jump();
                break;
            case FunnyRectChangeColorActionCode:
                var color = GenerateRandomColor();
                _view.ChangeColor(color);
                break;
        }
    }
    private void OnRotationEnd(object sender, EventArgs e)
    {
        _view.EnableInput();
    }
    private void OnJumpEnd(object sender, EventArgs e)
    {
        _view.EnableInput();
    }
    private Color GenerateRandomColor()
    {
        var random = new Random();
        var c = Color.white;
        c.r = (float)random.NextDouble();
        c.g = (float)random.NextDouble();
        c.b = (float)random.NextDouble();
        return c;
    }
    private int GenerateRandomAction()
    {
        var random = new Random();
        return random.Next(FunnyRectRotateActionCode, FunnyRectChangeColorActionCode+1);
    }
    public void Initialize()
    {
        _view.Clicked += OnRectClicked;
        _view.RotationEnd += OnRotationEnd;
        _view.JumpEnd += OnJumpEnd;
        _view.EnableInput();
    }
    public void Uninitialize()
    {
        _view.Clicked -= OnRectClicked;
        _view.RotationEnd -= OnRotationEnd;
        _view.JumpEnd -= OnJumpEnd;
    }
}

I think that this code is quite simple and straightforward. The Initialize event occurs subscription generated in the representation in Uninitialize unsubscribing from them. The constructor stores a reference to the idea. OnRectClicked method is called each time when the player clicks on the rectangle. It is generated random actions and calls the appropriate method of presenting it. You're looking at the code and IFunnyRectView IFunnyRectPresenter.

IFunnyRectView:

public interface IFunnyRectView 
{     
    event EventHandler RotationEnd;
    event EventHandler JumpEnd;
    event EventHandler Clicked;
    
    void EnableInput();
    void DisableInput();
    void Rotate();
    void Jump();
    void ChangeColor(Color color);
}

IFunnyRectPresenter:

public interface IFunnyRectPresenter
{
    void Initialize();
    void Uninitialize();
} 

Application MVP gave us the opportunity in the future to change the presentation logic in our sole discretion without affecting the application logic. It is also necessary to note that based on the concepts of MVP, you must avoid direct calling methods and setting properties of the Presenter presentation. Instead, it must be notified of the occurrence of certain events.

Full source code with comments, you can take the github.com/rumyancevpavel/FunnyRect.

 

 

 

 

 

 

User replies

No replies yet