Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[article] Unity with MVC: How to Level Up Your Game Development

Discussion in 'Community Learning & Teaching' started by eduardo-pons, Jul 30, 2015.

  1. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
  2. JoakimCarlsson

    JoakimCarlsson

    Joined:
    Aug 27, 2014
    Posts:
    65
    Pretty cool, I'm a big fan of the MVC pattern.
    Going to bookmark this for later.
     
    eduardo-pons likes this.
  3. OboShape

    OboShape

    Joined:
    Feb 17, 2014
    Posts:
    836
    Nice read, cheers for that :)
     
    eduardo-pons likes this.
  4. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    Thank you guys!
     
  5. GKiernozek

    GKiernozek

    Joined:
    Nov 16, 2013
    Posts:
    38
    Great job! Thanks for sharing! :) Best article about MVC I've seen

    I have a question - should i use a mini MVC model for bigger components? like the bigger elements take care about themselves like bigger sound manager inside game, that still wants only info from controller what sound to play, but uses self model view? and controller to controll that sound and data?

    BTW - asset store link doesn't work on https://bitbucket.org/eduardo_costa/thelab-unity-mvc/overview
     
    Last edited: Aug 7, 2015
  6. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    The Asset store is still under approval!
    You can use it following the Bitbucket instructions.

    Using the example of "Sound Playing", I usually have something like this:

    Code (CSharp):
    1.  
    2. //AudioView.cs
    3. class AudioView : View
    4. {
    5.   AudioSource[] audios;
    6.  
    7.   void Start() {  audios = GetComponentInChildren<AudioSource>();  }
    8.  
    9.   public void Play(string name,float time) { list.Find(name).Play(time); }
    10.  
    11.   public void Stop(string name) { list.Find(name).Stop(); }
    12.  
    13.   public void Stop() { foreach(AudioSource a in list) a.Stop(); }
    14.  
    15. }
    16.  
    17. //GameController.cs
    18. class GameController  : Controller
    19. {
    20.  
    21.   override public void OnNotification(...)
    22.   {
    23.     if("player-hit") app.view.audio.Play("player-hurt",0.0);
    24.   }
    25. }
    The AudioView is responsible by holding the audios inside it and playing when some controller order it.
     
  7. TheCaptainJuneBug

    TheCaptainJuneBug

    Joined:
    Sep 29, 2013
    Posts:
    9
    Hey, awesome framework!!!! I am trying to implement this framework into my existing game, the only thing i am confused on is how do i handle multiple of the same object as a view. For example i'm working of the your bouncy game example. What if i wanted to have multiple balls bouncing and want each ball to have a condition where it stops bouncing.

    Like right now i have one controller and one model, but instances of the ball in the game scene, so when a ball lands it talks to the controller than it adds a bounce to the model. I hope this makes sense.
     
  8. SubZeroGaming

    SubZeroGaming

    Joined:
    Mar 4, 2013
    Posts:
    1,008
    Good read. Well described. I've had experience in the past with MVC but never considered implementing it with Unity. Not a bad idea.

    Nice Job.
     
  9. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    For this simple example I would have the GameController and BallView have:

    Code (CSharp):
    1. public class BallView
    2. {
    3.   public int bounce; //current bounce count
    4.   public int maxBounce; //max allowed bounces
    5.   /*...*/
    6.  
    7. }
    8.  
    Code (CSharp):
    1. class GameController
    2. {
    3.   public void AddBall(Vector3 p_position,int p_max_bounces)
    4.   {
    5.      BallView b = Instantiate<BallView>(ball_template);
    6.      b.transform.parent = app.view.game;
    7.      b.maxBounce = p_max_bounce;
    8.      b.bounce = 0;
    9.   }
    10.  
    11.   public void OnBallBounce(BallView p_ball)
    12.   {
    13.     p_ball.bounce++;
    14.     if(p_ball.bounce >= p_ball.maxBounce) Destroy(p_ball.gameObject);
    15.   }
    16. }
    Considering that the "maxBounce" is related to the Ball itself, the MVC pattern is kept clean.

    For more complex games where we have like Player + Monsters with Classes. Usually I create some enumerations.

    Code (CSharp):
    1. public enum HumanClassType
    2. {
    3.   Archer,
    4.   Warrior,
    5.   Wizard
    6. }
    7.  
    8. public enum MonsterClassType
    9. {
    10.   OrcSmall,
    11.   OrcBig,
    12.   OrcLord,
    13.   SlimeBoss
    14. }
    and create a Model class structure that contains attributes for each enumeration.

    Code (CSharp):
    1. public HumanModel
    2. {
    3.   public HumanClassType type;
    4.   public float life;
    5.   public float mana;
    6.   public float strength;
    7.   public float dex;
    8.   public bool canCast;
    9.   public List<Spell> spells; //something like SpellModel
    10. }
    11.  
    12. /* something similar for the MonsterMoldel */
    In the hierarchy we create one GameObject for each HumanModel, fill the desired information and select the enum type.

    In the PlayerView we would have:

    Code (CSharp):
    1. public class PlayerView
    2. {
    3.   public HumanModel model; //reference to the chosen player class + stats to be used during gameplay
    4.   /* other info */
    5. }
    6.  
    7. public class GameController
    8. {
    9.   public void AddPlayer(HumanClassType p_type)
    10.   {
    11.    
    12.     PlayerView p = app.model.game.FindHumanTemplate(p_type); //searches the player prefab based on type.
    13.    p = Instantiate(p); //duplicate it.
    14.    p.model = app.model.game.FindModelByHumanType(p_type); //sets the current Model based on the player class.
    15.   }
    16. }
     
    ritesh_khokhani likes this.
  10. devotionsolutions

    devotionsolutions

    Joined:
    Feb 9, 2013
    Posts:
    40
    Hey, any update on getting approval on Asset Store?
     
  11. ChicK00o

    ChicK00o

    Joined:
    Feb 26, 2014
    Posts:
    13
    The architecture idea is very well explained in the article for clarity and control, and your modifications make a lot of sense. Just for addition, adding something like Zenject IOC [or any IOC] framework would further help in removing dependency around the classes, as well as the whole system would benefit a lot, by some event bus architecture, for replacing the Notification idea, where we loop all the controllers, and handle execution using switch-case.
     
  12. ricardoamaro

    ricardoamaro

    Joined:
    Apr 5, 2016
    Posts:
    1
    We are doing analysis of the framework right now.
    Would you say that this is a pure MVC Implementation or a MediatingController MVC?
     
  13. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    Good Point!
    Checking Wikipedia, I would say it is the Mediating Controller type.
    Model data can only be changed by Controllers.
    Views can only access/use Model's data at most.

    So all decision making pertaining the app as whole is decided inside one or more Controllers.
     
  14. jaf66

    jaf66

    Joined:
    Mar 31, 2016
    Posts:
    1
    Hi Eduardo,

    Great your framework about using MVC pattern on unity.

    I'm a old.. old VB.net (WebForms) programmer with lots of dificulties to turn my mind over MVC, and a new (Last month) Unity explorer.

    Now my question: after looking to some unity tutorials I was expecting to find a awake or start method to be fired when your Bounce example starts, how ever your app starts with OnNotification method.
    Can you give an idea on this, or send some link about it.

    Thanks a lot.
     
  15. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
  16. Aenigmaticus

    Aenigmaticus

    Joined:
    Apr 7, 2016
    Posts:
    54
    Thank you very much for the skeleton structure I can use to build my rather complex game... I was meaning on figuring out an implement of MVC in Unity, and your AMVCC will serve well for its purpose! Much appreciated for sharing your hard work, Eduardo!

    Also, this is the single best online example of the MVC pattern I have read! And I've been reading coding content for over a decade now...
     
    Last edited: Apr 20, 2016
  17. Aenigmaticus

    Aenigmaticus

    Joined:
    Apr 7, 2016
    Posts:
    54
    I'm inspecting your code and comments from Bitbucket... Your code is so clean and elegant! I'm going to take some pointers from this... pun not necessarily intended :p. Impressive use of inlining techniques! And clean generic types! Kudos Eduardo!
     
    Last edited: Apr 20, 2016
  18. Aenigmaticus

    Aenigmaticus

    Joined:
    Apr 7, 2016
    Posts:
    54
    Code (CSharp):
    1.         public void Log(object p_msg, int p_verbose = 0) {
    2.             //Only outputs logs equal or bigger than the application 'verbose' level.
    3.             if (p_verbose <= app.verbose) Debug.Log(GetType().Name + "> " + p_msg);
    4.         }
    Shouldn't the operator in the if-conditional be ">=" as per the comment above in the element.cs?
     
  19. glad

    glad

    Joined:
    May 10, 2014
    Posts:
    76

    You search every time you use app in your code ???

    Excuse me if I am wrong.
     
  20. abesmon

    abesmon

    Joined:
    Apr 25, 2016
    Posts:
    1
    I'm not a genius (just few weeks in Unity), but it's seems to me like this:
    We have private variable m_app,
    then, at first request to app, it uses Assert(), that takes 2 arguments.
    Using first variable Assert does this: if it's null, then looks for <T> object, if not null, then return this variable.

    So, as i see it's only looks for object only first time, when m_app is not initialized
     
  21. WindwalkerDM

    WindwalkerDM

    Joined:
    Feb 14, 2015
    Posts:
    10
    Could someone also help with how to handle level transitions with such a setup? What should I do when I load the next level? Which objects should I keep and which to discard and how to setup such things? I am really looking forward to implementing in a sample shoot-em up game to test the waters. Thanks in advance.
     
  22. gyhser

    gyhser

    Joined:
    Jan 8, 2017
    Posts:
    2
    Looking to shed some light on this as well. Eduardo noted on toptal.com that

    So according to these hints, it would seem what needs to be done is to have a persistent SceneModel, SceneController and SceneView and on load you interchange the scene specific items aka controller/view/model per scene. Correct me if I'm wrong but that would mean not destroying the base application, scenemodel, scenecontroller and scene view on scene load. Which would require you to unparent any unnecessary objects from the base application before the scene is changed because every child inside an object targeted with DontDestroyOnLoad() will persist. I will report back here once I create a working example but would appreciate any extra help.
     
  23. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    No need to use DontDestroyOnLoad (unless you have some real persistent instance needed).
    On each scene change we destroy the "app.view.*" "app.controller.*" and "app.model.*" structure from that scene.

    Those will be created/destroyed every time (no harm in doing that)
    app > Always on all scenes
    app.controller > Root controller always on scenes
    app.view > Root view always on scenes
    app.model > Root model always on scenes
    ----

    Example Root controller to startup a "load.unity3d" scene:
    app.controller.load (will exist in load.unity3d and be null in all other scenes)

    Example Root controller to startup a "game.unity3d" scene:
    app.controller.game (will exist in game.unity3d and be null in all other scenes)

    Usually the first code to be executed on a scene will be those above. In Root Controller "app.controller" a more generic initialization per scene will happen (i.e. Re-Apply GraphicSettings or some special initialization that always is needed, like IsLogged check)
     
  24. gyhser

    gyhser

    Joined:
    Jan 8, 2017
    Posts:
    2
    Thank you for the quick reply! With your advice in mind I went over the code again and I now understand the basic logic for creating new scenes with scene specific models, views, and controllers. I built an example based off your BitBucket project for a multi-scene application but I am still scratching my head about persistent data between scenes. Currently I have an object titled Persistent that has DontDestroyOnLoad which would store models,controllers or views I would want to keep between scenes. Then in each root scene model,view or controller I Assert using the global flag to find these objects.

    The following is my load scene with the Persistent object hanging outside the application. This automatically loads a scene called cubeScene.



    Now in this scene I can access everything under the Persistent object by asserting using the global flag, see my SceneModel.cs (application.model) as an example on how I access my GameModel.cs




    Code (csharp):
    1. public class SceneModel : Model<multisceneApplication>{
    2.  
    3.     public GameModel Game { get { return m_game = Assert<GameModel>(m_game,true); } }
    4.     private GameModel m_game;
    5.  
    6.     public CubeModel Cube { get { return m_cube = Assert<CubeModel>(m_cube); } }
    7.     private CubeModel m_cube;
    8.  
    9.     public SphereModel Sphere { get { return m_sphere = Assert<SphereModel>(m_sphere); } }
    10.     private SphereModel m_sphere;
    11. }
    What do you think, how would you recommend storing persistent data and the like between scenes?
     
  25. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    Yep that is a way!
    I try keeping the use of DontDestroy to a minimum.

    Usually I have a SceneArgs component with DontDestroy and use it as bridge between scenes to carry data.

    app.args.SomeData = "Value to Next Scene"; //app.args is the reference to the DontDestroy SceneArgs component

    LoadScene("next-scene");

    Debug.Log(app.args.SomeData);

    Though some elements must be kept on DontDestroy (like Profile login/session data)

    Then stick all the time with:

    (will be always destroyed/created)
    app
    controller [is always created between scenes]
    load [for load scene]
    main[for main scene]
    game[for game scene]
    model
    load [for load scene]
    main[for main scene]
    game[for game scene]
    view
    load [for load scene]
    main[for main scene]
    game[for game scene]
     
  26. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    856
    Do you use Physics in View or model?
    UIs,Renderer,Cameras all are in view but I think that physics component should be used in a model not a view. I mean if you want to move your object with force or other ways, you implement it in a view and use only fields like force,etc from a model?

    If your model does not use any unity components, so it is more suitable to be a classic plain c# class
    One question:
    Your views can interact together with referencing (find,getcomponent,etc)
    Can controllers interact together as well?
     
    Last edited: Jan 24, 2018
  27. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    856
    I think it is better to minimize controllers whatever you want. Instantiating can be done in a view function like CreateBall() with some parameters called from the controller
     
  28. Saikat_2016

    Saikat_2016

    Joined:
    Dec 21, 2016
    Posts:
    10
    The framework is great. I have used it. Actually I am new comer. I have little doubt that
    1. If I want to initialize something in this pattern then where how to initialize method will call?Is this in Root Controller or View or Model or elsewhere
    2. In the source directory there is a view directory. Under this folder there are lots of View scripts like AnimationView, AnimatorView, NotificationView, ColliderView, TriggerView also some UI view like ButtonView, DragView, DropView etc under UI folder can you explain in brief way that where when and how those view script will use? I can't understand totally.
     
  29. gustavo_npimentel

    gustavo_npimentel

    Joined:
    Feb 5, 2014
    Posts:
    1
    Hello!
    How can i use multiples models and controllers for a big project?

    Exemple: I want to create a PlayerController, PlayerModel, MainModel, MainController, UIController, UIModel, but i dont understand how to build my hierarchy and where i put my components to it work fine.
     
  30. RodrigoAbreu

    RodrigoAbreu

    Joined:
    Jan 29, 2013
    Posts:
    12
    That's the ideal I guess, as having a single controller to rule them all breaks totally the single responsibility principle
     
  31. xqtr123

    xqtr123

    Joined:
    Jun 7, 2014
    Posts:
    20
    I'm wondering this as well. My collision detection is based on raycasting all around the player. Should this be in a view or in the model? What about movement? Should this be done in view or model?
     
  32. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    856
    I think it is better you do not use MVC at this situation.
    Use component based approach as Unity has implemented
     
  33. RedHotFlashman

    RedHotFlashman

    Joined:
    Mar 16, 2018
    Posts:
    35
    There is no InitializeController or AddController function anywhere. Does this mean I have to add every controller by using AddComponent on an existing GameObject in the scene? Or are all notifications handled in one Controller?