To begin with, I’ll say that I’m a big MVC supporter and don’t recognize (see?) Other options for organizing code. Already had a successful experience of applying this idea in PHP, and I really liked it there - probably the reason. Now I get acquainted with Unity, C # and development of games in general. Only here I will not understand something in any way how to apply this idea in Unity. I had a chance to gossip about MVC in Unity and I realized that people don’t welcome this idea (and for good reason), but, nevertheless, it is possible. The question is ... What will the controllers? Where will the model be located? How to work with View? And how to connect all this?

PS If you are well versed in this matter and think differently, then I don’t mind if you persuade me of the need for MVC when developing a game for Unity, but please try to explain your point of view. :)

PPS This is my first question here. Prior to that, I often visited here, found questions of interest and answers to them. Now I decided to ask myself. =) Hopefully, kindly accept. : p

  • Well, the classic MVC alternative is MVP / MVVM (used in WPF). - VladD
  • @VladD I have not heard about MVP. Now at least I see in which direction to dig, thanks. You will not try an example (in the case of Unity)?) I would be just happy. :) - JerryGreen
  • @JerryGreen: No, I can not, I'm not a big specialist in Unity. According to WPF there are many examples on the site, for sure it is easy to google. - VladD

2 answers 2

From the experience of studying various starter whales, I can assume that at the moment developers using Unity, in general, very rarely use any generally accepted programming patterns. For myself, I see the reason for this in the short life of the game as a product, plus the specificity of Unity itself. One, two - and in production, so to speak.

If we talk about how to organize the user interface, for myself, I decided that the optimal work model would be something similar to MVVM, plus the Team template.

In the scene we create a user interface, then a manager object, which will be responsible for integrating the interface with logic. Let's call it, for example, GUIImpl . The class must be MonoBehaviour successor in order for us to work with it in the editor. In the example below, I use NGUI for the interface itself.

The next step is to create a class description of the graphic element, for example, a panel. I make this class intrinsic to GUIImpl , but it's not for GUIImpl .

 [System.Serializable] public class MenuPanel : GUIMenuBase { public GameObject SettingsButton; public GameObject CancelButton; public GameObject ExitButton; public GameObject ResetButton; public override void Init() { associateButton(NewGameButton, new NewGameCommand(this)); associateButton(SettingsButton, new SettingsCommand(this)); associateButton(CancelButton, new CancelCommand(this)); associateButton(ExitButton, new ExitCommand(this)); } public override void Show() { base.Show(); } public override void Hide() { base.Hide(); } } 

As you can see, the panel class is a descendant of GUIMenuBase . This class is specific to your user interface. I will give my basic functionality.

 [System.Serializable] public abstract class GUIMenuBase : IGUIMenu { public GameObject Instance; protected Dictionary<GameObject, ICommand> associations = new Dictionary<GameObject, ICommand>(); protected List<GameObject> activeButtons; public GUIMenuBase() { } public abstract void Init(); public GameObject GetGOInstance() { return Instance; } public virtual void Show() { GUILogic.ShowMenu(this); } public virtual void Hide() { GUILogic.HideMenu(this); } public virtual bool CanShow(GameObject guiItem) { return true; } public virtual bool IsShown(GameObject guiItem) { return true; } public virtual bool IsAvalibale(GameObject guiItem) { return true; } public virtual bool CanButtonClick(GameObject button) { if (!associations.ContainsKey(button)) return false; return associations[button].CanExecute(button); } public virtual void ButtonClick(GameObject button) { if (!associations.ContainsKey(button)) return; if (associations[button].CanExecute(button)) associations[button].Execute(button); } public virtual void OnSourceChanged() { foreach(var item in associations) { UIButton buttonScript = item.Key.GetComponent<UIButton>(); if (buttonScript != null) { buttonScript.isEnabled = item.Value.CanExecute(item.Key); buttonScript.enabled = true; } } } protected virtual void adjustPanelButtons() { } protected virtual void associateButton(GameObject guiItem, ICommand command) { associate(guiItem, command); UIEventListener.Get(guiItem).onClick += ButtonClick; } protected virtual void associate(GameObject guiItem, ICommand command) { associations.Add(guiItem, command); } protected virtual void removeAssociation(GameObject guiItem) { if (associations.ContainsKey(guiItem)) associations.Remove(guiItem); } } 

Iguimenu

 public interface IGUIMenu { void Show(); void Hide(); bool CanShow(GameObject guiItem); bool IsShown(GameObject guiItem); bool IsAvalibale(GameObject guiItem); bool CanButtonClick(GameObject button); void ButtonClick(GameObject button); void OnSourceChanged(); } 

IGUIMenu contains methods for working with various elements. I brought the interface to work only with buttons. Next, we implement the action by clicking on the buttons.

 public class NewGameCommand : CommandBase { public NewGameCommand(GUIMenuBase aPanel) : base(aPanel) {} public override void Execute(GameObject button) { if (!CanExecute (button)) return; DatabaseManagerFactory.GetDefaultDatabaseManager().Reset(); Application.LoadLevel(Application.loadedLevel); } } public abstract class CommandBase : ICommand { protected GUIMenuBase panel; public CommandBase(GUIMenuBase aPanel) { panel = aPanel; } public virtual bool CanExecute(GameObject button) { return true; } public virtual void Execute(GameObject button) { } } public interface ICommand { void Execute (GameObject context); bool CanExecute (GameObject context); } 

Basically, that's all. It remains only to implement the class GUILogic , which contains the logic of the panels. Then open the editor, find our object to control the user interface, and assign the elements of the various panels to the corresponding fields. Thus, for each panel should be its own class, which contains all the necessary fields. Please note the public GameObject Instance; field public GameObject Instance; class GUIMenuBase . Instance is an object of the panel itself. For most panel operations, we need its root element.

  • @Expert ♦♦ Wow! Well, you give ... I expected at best only superficial explanations in one or two paragraphs, and you gave me a real example :) I feel for a long time I will understand. But thank you :) In PHP, it was somehow simpler: D By the way, you don’t give lessons / you don’t have a YouTube channel?) Or at least a blog?) I feel you could teach a lot :) - JerryGreen
  • one
    @JerryGreen, I will be glad to answer your questions on Unity on the forum. - Nicolas Chabanovsky

Sorry for raising the old topic, but there is an easier way.

First, instead of the event system, use controller variables.

 class Controller: MonoBehaviour { Object data; Component instance; String ctrl_name = "MyController"; void Awake() { instance = gameObject.GetComponent(ctrl_name); } void Load(name, data) { Component c = gameObject.AddComponent(name); c.ctrl = instance; c.data = data; } } class MyController: Controller { MyModel model; Object mouse; Object key; Start() { model = new MyModel(0,3,150,["model1","mass"]); Load("MyView", model.data); Load("MyInterface", null); Load("MyInput", null); } } class View: MonoBehaviour { Component ctrl; Object data; } class MyView: View { void Update() { if (ctrl.mouse.down) DrawModel(data["circle"]); } } 

Secondly, you can dig in the direction of NData:

tutorial: http://gcup.ru/forum/59-27429-1