Search Unity

MVVM and DataBinding in Unity

Discussion in 'Scripting' started by pahe, Oct 22, 2012.

  1. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Hi folks.

    I'm currently setting up a MVVM system by myself, but I'm rather unsure if I'm on the right track, so I post here some code just to hear if you guys could tell me if it's the right direction or what I can do better.

    Mostly the DataBinding part is something I think I haven't got into yet so here's what I have till now:

    ViewModel class
    Code (csharp):
    1.  
    2. public class ViewModel : MonoBehaviour
    3. {
    4.     #region Data
    5.     private DataObj _data;
    6.     internal DataObj Data
    7.     {
    8.         get { return _data; }
    9.         set
    10.         {
    11.             _data = value;
    12.             if (DataChanged != null)
    13.                 DataChanged(_data);
    14.         }
    15.     }
    16.  
    17.     internal event Action<DataObj> DataChanged;
    18.     #endregion
    19.  
    20.     private void Start()
    21.     {
    22.         Data.PropertyChanged += Data_PropertyChanged;
    23.     }
    24.  
    25.     private void OnDestroy()
    26.     {
    27.         Data.PropertyChanged -= Data_PropertyChanged;
    28.     }
    29.  
    30.     void Data_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    31.     {
    32.         Data = (DataObj)sender;
    33.     }
    34. }
    35.  
    View class
    Code (csharp):
    1.  
    2. public class View : MonoBehaviour
    3. {
    4.     [SerializeField] private ViewModel viewModel;
    5.  
    6.     [SerializeField] private Sprite sprite;
    7.     [SerializeField] private TextMesh text;
    8.  
    9.     private void Awake()
    10.     {
    11.         // play slide in animation
    12.         viewModel.DataChanged += viewModel_DataChanged;
    13.     }
    14.  
    15.     private void OnDestroy()
    16.     {
    17.         viewModel.DataChanged -= viewModel_DataChanged;
    18.     }
    19.  
    20.     void viewModel_itemDataChanged(DataObj obj)
    21.     {
    22.         UpdateUI(obj);
    23.     }
    24.  
    25.     void UpdateUI(DataObj obj)
    26.     {
    27.         sprite = new Sprite(obj.spriteName);
    28.         text = obj.text;
    29.     }
    30. }
    31.  
    As you see my ViewModel class is handling the communication to the data model and will throw an event when new data is arriving. The View is listening and updating all UI elements it knows.

    Now here's the first part I'm unsure about: Is it actually good that I have this (at the moment) small view class, which knows all UI elements in my scene and updates them or is it better to have several smaller view class, e.g. SpriteView, TextView and these all share the same viewmodel?

    Second question is about the data binding. For now this is only a one way data binding, the logic gets new data, throws event and view will update. But how do I a two way binding? My first approch was to add to my view class:

    Code (csharp):
    1.  
    2.     void UpdateText(string newText)
    3.     {
    4.         viewModel.Data.text = newText;
    5.         UpdateUI(viewModel.Data);
    6.     }
    7.  
    but I'm not feeling good about that. Though it works, it doesn't seem to me like the right way to do it in that pattern.


    So I hope you guys could give me some comments about it and maybe what I should improve.

    Many thanks,

    pahe



    PS: I know there is something like NData or EZData, but either plugin will need the UI framework too, which is over my budget. Additionally I would like to understand the full pattern first before buying a plugin which does what I want to understand.
     
    Last edited: Oct 22, 2012
    CunningFox146 likes this.
  2. micahoz123

    micahoz123

    Joined:
    Jul 21, 2013
    Posts:
    34
    I just released a plugin for MVVM on the asset store. Its a professional framework not just for UI. It has very strong binding support via code or components. It could really save you a-lot of time. The video tutorials and api documentation will really help you get started. I've built 2 games small and large using it and i don't want to ever use anything else.. For a veteran programmer like me it just makes thing so much more fun. You can take a look here :D

    https://www.assetstore.unity3d.com/#/content/14381

    Even if you're not interested i think you're on the right track with MVVM it's perfect for games.
     
  3. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Hi, Pahe!
    I'm confused a little bit.
    Does System.ComponentModel.PropertyChangedEventArgs will work in other platforms besides Windows standalone?
     
  4. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    MVVM for games is overkill... so is MVC... mildly useful for UI, but thats it.

    I dont think there are any patterns that are good for games other than singletons, especially in unity.
     
    TzuriTeshuba likes this.
  5. micahoz123

    micahoz123

    Joined:
    Jul 21, 2013
    Posts:
    34
    Overkill? And 100's to thousands of random components (that somehow interconnect with each other that you have to connect by dragging and dropping everything in unity) isn't?

    IMHO I somewhat disagree with you James. MVVM is a great model for building games that are more data-centric like MMO's and strategy games. Singletons isn't necessarily a bad thing in some cases. But singletons are way over used when programmers are lazy. Its provides global access and couples anything that uses it. This makes things way to easy to break. Especially as a game grows. But I've been developing software and games for over 15 years using these kinds of patterns so maybe i can see how it fits easier than others.

    Now for smaller games like a ball rolling game or something it probably doesn't make sense and could be considered overkill.

    Again this is just my opinion. People develop games all the time without things of this nature. I even have more than few times.. Maybe i'm crazy but i never want to go back to that madness.
     
  6. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Yes, that works. We have actually finished the development on that and it works (with some minor workarounds to our own GUI design flaws). We use it also on mobile, so, though we haven't profiled it, we hadn't had any performance problems at least with that.

    Well... I would say as with other design pattern it depends on the game/application you would like to create. Not much UI or want to make the next Flappy Birds? Maybe too much overhead if you have to implement the system from the scratch. Very many many other applications I can only recommend that pattern, as it solved for us many problems and reduced code duplication a lot (as you have then to find a way to update your UI by yourself).

    So I guess I agree with micahoz123 and afaik Unity themselves are considering to implement something like MVVM for the new UI system (take that with much salt).
     
    Patico likes this.
  7. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    If you're dragging and dropping anything, you're doing it wrong... for someone with 15 years experience I would expect more...

    Size of game would play a large part, but it would have to be of MMO level to be worth it... most games made with Unity dont even come close to reaching that level of scale.

    Singletons suit Unitys component based model more than MVVM/MVC ever will. MVVM is my all time favourite pattern, but ill never even consider putting it into Unity, unless Unity integrates a XAML approach to UI.
     
  8. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Every design pattern handles specific problems. I wouldn't say that singletons do the same as a MVVM pattern, but it may solve similar problems. It's all up to what's your current development problem is.

    From my experience with the MVVM pattern, I can only suggest that everyone with an UI that needs frequent updating with changing data should consider to have a look into the pattern and consider to use it.
     
  9. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    Singletons are nothing like MVVM... I wasnt suggesting they were.

    You're trying to use a business application pattern in a game... fine. Do what you want.

    MVVM is the best when it comes to desktop applications, especially db driven, but unless like I said youre creating something with a vast amount of constant UI change (which immediately excludes 90-95% of games), its overkill.
     
  10. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    MVVM will end up feeling really clumsy without really good data binding. You really can't execute a good mvvm implementation without something to cover the data binding. That said, you can build something pretty easily to cover the idea of data binding.

    You could do something like an object that encapsulates the change notification and the value itself. Like a property object. But that will generally introduce some awkward semantics.

    Personally, I like pub/sub notification better than databinding for notification of game state change during play.

    I also prefer some kind of dependency injection or something as opposed to singletons. But to each their own.


    Also worth noting:
    The trick with mvvm and databinding really comes down to the same 'kind' of change having the same result every time. But the problem is that games tend not to work this way. An example would be:

    HP Change - in a desktop app - hp change would generally be represented by changing the text value of a label. You don't care WHY it changed, or HOW it changed, you only care that the value changed. Since you only care that there's a new number there, you only need to know that a given property has changed.

    HP Change - in a game - in this case you very often want to know WHY and HOW it changed. You want to pop a blood particle that bursts in the direction of the attacker. You want to stagger the character backward from the attack by some distance. You want to know how much changed, so you know how much blood to squirt.

    That's part of the reason I tend to think databinding is not good for 'gameplay' because most of the time raw property bindings won't include enough information. To achieve that kind of information involves some really fugly nail hammering.
     
    Last edited: Aug 25, 2014
  11. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    @frosted:

    I can't fully agree as it depends too much on the type of game and the architecture of your code if MVVM is handy or not. In our case, we have an online MMO where the player sees his stats in the client but all changes are done on the server. So in this case, we don't care why or how the values are changed (for example the health), but we want to display the change of its value if it is send by the server.
    But I agree, if you have something like Diablo and you want to react to health points loss and has to find out why and how it came to be, then I wouldn't do it via MVVM neither (or so I think at least).

    Again: the MVVM pattern is to solve coding problems and of course it isn't a solution for everything or it should be enforced to use. If you face the problem that you have changing data and have a loot of UI elements which are listening to that data changes, you should consider using the MVVM pattern (though you might realize that it may not fit in your implementation).
     
  12. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Fair enough pahe, just keep in mind that main limitation - mvvm will not provide context for change - just a raw value. So any kind of reaction that requires more information will give you problems.

    So to address your main concern, I would steer away from the actual wpf propertychange and do something like the following.
    Code (csharp):
    1.  
    2. delegate void Changed<T>(T current, T old);
    3.  
    4. public class Property<T>{
    5.   public T Value{
    6.     get{ return m_Value; }
    7.     set{
    8.       if( m_Value == value ) return;
    9.       var o = m_Value; m_Vaue = value;
    10.       Changed( value, o );
    11.     }
    12.    public event Changed = delegate{}
    13. }
    14.  
    Using this has a few advantages - the main being that you know which property is being changed without doing some kind of string based lookup. You also at minimum have two values old, and new coming out of the delegate. Your classes can declare these as readonly. Additionally, if you pop in a non generic base, you can dump a set of them into a list.

    So you would use them like this:
    Code (csharp):
    1.  
    2. public class Dude{
    3.   public readonly Property<int> HealthProp = new Property<int>( DEFAULT_HEALTH );
    4. }
    5.  
    6. public class HealthBar : MonoBehaviour {
    7.   private Dude m_CurrentBoundDude;
    8.   public void ShowDudeHP( Dude d ){
    9.     if( m_CurrentBoundDude != null ){ m_CurrentBoundDude.HealthProp.Changed -= HandleChange; }
    10.     m_CurrentBoundDude = d;
    11.     m_CurrentBoundDude.HealthProp.Changed += HandleChange;
    12.   }
    13.   public void HandleChange( int current_health, int old_health ){
    14.      label.text = current_health;
    15.   }
    16. }
    17.  
    The semantics can get a little ugly with the .Value - but IMO it's worth it to avoid string based lookups and S***.

    I would again, consider using some kind of pub/sub or message based system instead of mvvm honestly. But good luck.

    Edit:

    Also - one other limitation with using any kind of delegate based property listener approach is that your events will always fire in a stack. This can be problematic at times if you have events that cause other events to fire, the last event will always resolve first.

    Let's say that you have some event somewhere:
    HealthChanged

    You have some other component somewhere else listening to HealthChanged. It fires
    CharacterDead
    when your character has 0 hp.

    A, B, C are listening for both of those events and are subscribed in that order. B is the subscriber that fires CharacterDead. The execution will look like this:

    A.HealthChanged()
    B.HealthChanged();
    B.FireCharacterDead()
    A.CharacterDead();
    B.CharacterDead();
    C.CharacterDead();
    C.HealthChanged(); // C already handled CharacterDead and is now getting Health Changed.

    This is a horrible example admittedly, but you almost never really want your events fired in a stack. Using some other system allows you to guarantee execution as a queue.
     
    Last edited: Aug 26, 2014
  13. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I skipped over michah link at first pass. But I will say, uFrame looks pretty impressive. I was thinking about buying it a few weeks ago to play around. Visual tools have really come a long way.
     
  14. junedmmn

    junedmmn

    Joined:
    Dec 19, 2016
    Posts:
    15
  15. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,443
    @junedmmn, another necropost. Please please look at the post you're replying to. It's ELEVEN YEARS OLD. Dead and buried. Mountains have fallen and oceans dried up in that amount of time, and APIs have changed significantly.
     
  16. mrwellmann

    mrwellmann

    Joined:
    Nov 27, 2015
    Posts:
    37