Search Unity

C# "Get and Set" functions and the Unity Inspector

Discussion in 'Scripting' started by Pto345, Dec 27, 2010.

  1. Pto345

    Pto345

    Joined:
    Aug 24, 2010
    Posts:
    42
    So, right now i am making a game where i have a player and his stats and a monster and their stats. I have the variables in private so that things cannot accidently manipulate them. But i also use the get/set functions to make the variables accessed if used correctly. However, the variables with the get/set do not show up on the inspector in Unity. Is there a way that i can make these variables show up without making the base variables public?

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class playerStats : MonoBehaviour {
    5.    
    6.     //these are the base variables; they cannot be seen by other scripts
    7.    
    8.     private int m_health = 10;
    9.     private int m_damage = 3;
    10.     private int m_strength = 2;
    11.     private int m_maxHealth = 10;
    12.     private int m_playerLevel = 1;
    13.     private int m_experience = 0;
    14.    
    15.    
    16.     // Use this for initialization
    17.     void Start ()
    18.     {
    19.        
    20.     }
    21.    
    22.     // Update is called once per frame
    23.     void Update ()
    24.     {
    25.        
    26.     }
    27.    
    28.     //these variables can be used by other scripts
    29.     //they take the values of the base variables
    30.     //however, they dont show up in the inspector
    31.    
    32.     public int health
    33.     {
    34.         get { return m_health; }
    35.         set { m_health = value; }
    36.     }
    37.    
    38.     public int damage
    39.     {
    40.         get { return m_damage; }
    41.         set { m_damage = value; }
    42.     }
    43.        
    44.     public int strength
    45.     {
    46.         get {return m_strength; }
    47.         set {m_strength = value; }
    48.     }
    49.    
    50.     public int maxHealth
    51.     {
    52.         get {return m_maxHealth; }
    53.         set {m_maxHealth = value; }
    54.     }
    55.    
    56.     public int playerLevel
    57.     {
    58.         get {return m_playerLevel; }
    59.         set {m_playerLevel = value; }
    60.     }
    61.    
    62.     public int experience
    63.     {
    64.         get {return m_experience; }
    65.         set {m_experience = value; }
    66.     }
    67.    
    68.     public void HurtMonster(int monsterHealth)
    69.     {
    70.         monsterHealth -= m_damage;
    71.     }
    72. }
    73.  
    P.S. If u couldnt tell by the title, i am using C#.
     
  2. tmanallen

    tmanallen

    Joined:
    Nov 8, 2009
    Posts:
    395
    If you want to see it in the inspector try this: Hopefully it works

    Code (csharp):
    1.  
    2. [SerializeField]
    3.     public int strength
    4.     {
    5.         get {return m_strength; }
    6.         set {m_strength = value; }
    7.     }
    8.     public int m_strength;
    9.  
    10.  
     
    ow3n likes this.
  3. pakfront

    pakfront

    Joined:
    Oct 6, 2010
    Posts:
    551
    oops, wrong (good)
     
    Last edited: Dec 27, 2010
  4. Pto345

    Pto345

    Joined:
    Aug 24, 2010
    Posts:
    42
    Sweet, the serilize field was exactly what i needed. I just needed to put it in front of my private variables like so:

    Code (csharp):
    1.  
    2. SerializeField]
    3.     private int m_health = 10;
    4.     [SerializeField]
    5.     private int m_damage = 3;
    6.     [SerializeField]
    7.     private int m_strength = 2;
    8.     [SerializeField]
    9.     private int m_maxHealth = 10;
    10.     [SerializeField]
    11.     private int m_playerLevel = 1;
    12.     [SerializeField]
    13.     private int m_experience = 0;
    14.     [SerializeField]
    15.     private int m_monsterHealth;
    16.  
    Now, do u know if i can put only one SerializeField in front of a block of code so that all of them can become serialized? And to clarify...these objects arent public, they are just seen in the inspector, right?
     
  5. JGeorge

    JGeorge

    Joined:
    Dec 14, 2010
    Posts:
    30
    I don't know offhand but a quick way to test it would be to create a public value of the same type that could be seen in the inspector, and in the update function assign the private variable's value to the public variable. Then try to change your serialied field and see what happens to your public value.

    Hope that makes sense.
     
  6. tmanallen

    tmanallen

    Joined:
    Nov 8, 2009
    Posts:
    395
    You could make it private and if I understand you question correctly try this:

    Code (csharp):
    1.  
    2. [System.Serializable]
    3.     private class Health
    4.     {
    5.         public int strength
    6.     {
    7.         get {return m_strength; }
    8.         set {m_strength = value; }
    9.     }
    10.     [SerializeField]
    11.     private int m_strength;
    12.     }
    13.     [SerializeField]
    14.     private Health health;
    15.  
    Hope this answers you question. Now I may be wrong but hope this helps.
     
  7. Chris-Sinclair

    Chris-Sinclair

    Joined:
    Jun 14, 2010
    Posts:
    1,326
    nope
     
  8. Luluandfriends

    Luluandfriends

    Joined:
    Mar 12, 2013
    Posts:
    2
    if they are all of the same type, sure, [SerialiazeField] applies to one line of code. For example:

    [SerialiazeField]
    private int m_health=10, m_damage, m_strength;
     
    Bunny83 likes this.
  9. EliteMossy

    EliteMossy

    Joined:
    Dec 2, 2012
    Posts:
    513
    Don't go necro posting. This thread was 3 years old.
     
  10. pixel_fiend

    pixel_fiend

    Joined:
    Jun 16, 2014
    Posts:
    4
    OCD much? It's still a relevant topic.
     
  11. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    [SerialiazeField] causes compiler warnings when building using Microsoft's .NET 4.5.1 instead of Mono.NET. Just in case you're doing a Windows Phone or Windows Store build.
     
  12. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Unity, by default, only displays in the Inspector what is SAVED or CAN be saved on the disk.

    Unity saves fields from a type deriving from UnityEngine.Object (MonoBehaviour/ScriptableObject), OR class with the [Serializable] attributes.

    Only public fields are saved by default. Private fields are ignored, unless flagged with [SerializeField].

    The Inspector will also ONLY display variable that Unity can save. For example, it will not display Hashtable, Dictionary, or nested list, because Unity is unable to save those types.

    The Inspector only display fields, and ignore properties (get/set), events and methods.

    If you want the inspector to work in any other way, you have to write your own Custom Editor. (Ex.: See my signature for Advanced Inspector)
     
  13. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    I've not used it myself, but the OnValidate method in a MonoBehaviour could be useful for using setter methods via a default Inspector.

    My untested assumption is that we could mark the backing fields with [SerializeField], make public setter methods which enforce whatever rules we want to have, and have an OnValidate method similar to the following:
    Code (csharp):
    1.  
    2. [SerializeField]
    3. private float privateBackingField = 0;
    4. public float PublicAccessibleProperty {
    5.     get {
    6.         return privateBackingField;
    7.     }
    8.     set {
    9.         privateBackingField = Mathf.Clamp01(value);
    10.     }
    11. }
    12.  
    13. void OnValidate() {
    14.     PublicAccessibleProperty = privateBackingField;
    15. }
    16.  
    I believe this would mean that every backing field is re-applied via its public property each time an Inspector value is changed. As long as you don't have any complex interdependencies between your properties this should be a pretty straightforward solution, in theory. (And even with complex interdependencies it shouldn't be that much more difficult, since you can just call whatever you're using to enforce them anyway.)

    Heck, I bet you could even use reflection magic to automate this from a common subclass of MonoBehaviour.

    Edit: Tested the above code. Works great. ;) I will totally be using and abusing this from now on. :D

    Edit 2: Of course the downside to this is that the getter isn't actually being used by the Inspector, so if we've got any kind of data transformation going on there it'll be getting ignored. So contrary to what I initially had written above, this is handy for applying rules on set but not so useful on get. For that I believe you would indeed need a custom Inspector, because you're looking to change the basic rules by which Unity displays stuff in there. (Or... hacky approach... have separate private backing fields for the Inspector and for runtime, and update the Inspector fields via their getters at the end of OnValidate... but that's really getting funky and I wouldn't want to maintain it on a large codebase, and it still wouldn't be particularly reliable for derived getters... I think a custom Inspector would be a clearer approach.)
     
    Last edited: Jun 20, 2014
  14. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You have it right that the getter isn't used... And in some cases - in some project I have been on - it wasn't enough. Data conversion between what is displayed and what is serialized is something we have done a lot of time.

    Using properties to convert a format Unity is able to save from and back to a format the user is able to read is quite useful.
     
  15. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Is it possible to write a generic custom Inspector? I know that if we have ComponentX that if we write ComponentXInspector it does its thing. But can we write BaseClass and then have BaseClassInspector, will BaseClassInspector be used for derived classes? (I'll test this myself if the answer isn't known.)
     
  16. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Yes, it's possible. It's how I built the Advanced Inspector. I created a Custom Editor for "MonoBehaviour", so all script pass by it.
     
  17. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Righto. I looked it up on the Asset Store and I reckon I might buy me a license tonight. :)
     
  18. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    An easier way to just see private variables in inspector (read only) is to put it into debug mode (top right corner). This way you don't have to mess around with all that attributes cluttering your code. If you need to save those values anyway go with serializefield.
     
  19. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Code (CSharp):
    1. OnValidate()
    is remarkably useful, for during development if nothing else. Thanks for that tip!

    It's basically undocumented.
     
    Tioboon likes this.
  20. lai32290

    lai32290

    Joined:
    Apr 2, 2016
    Posts:
    6

    Thank you so much!
     
    tmanallen likes this.
  21. goodseller

    goodseller

    Joined:
    Aug 25, 2016
    Posts:
    2

    OnValidate is really helping! Thanks from 2016. ;)
     
    angrypenguin likes this.
  22. jeancallisti

    jeancallisti

    Joined:
    Oct 27, 2017
    Posts:
    9
    EDIT: I did a colossal blunder. Shame. Especially in a necropost.
     
    Last edited: Feb 26, 2019
  23. ADNCG

    ADNCG

    Joined:
    Jun 9, 2014
    Posts:
    994
    Works fine for me. Maybe you are accidentally returning the property itself in the get accessor of your version?
     
  24. jeancallisti

    jeancallisti

    Joined:
    Oct 27, 2017
    Posts:
    9
    You've been too quick! No, but still, it was a mistake on my part. Apologies for necroposting.
     
  25. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    513
    First people complain when you create a NEW post on a topic that's already been discussed.
    Then people complain that you open this OLD post despite the above.

    <Proud 'necroposter' cause its better if it's all in one place > ** /sigh
     
    Aethenosity and glowkeeper like this.
  26. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Necro-posting is fine as long as it contributes to the original topic.
    This post you made just now does not. Nothing to be proud of.
     
  27. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    513
    = Irony
     
    FetchQuestGames likes this.
  28. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Yes, I see the the irony in my response.
    Point still stands.
     
  29. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    You must be at least 10 years of age by now going by your join date, why is it that you're acting like a 3 year old?
     
    Aethenosity likes this.
  30. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Since I just got a "like" on that post, an update may be in order.

    First, for some things Unity now has attributes that can allow you to enforce simple rules on Inspector fields. Stuff like [Min(0)] and so on are super handy. Still doubling up on setters for applying constraints, but perhaps better than the hack I raised earlier. Up to personal taste.

    Second, in my code I've been removing a bit of use of OnValidate of late. For trivial stuff it's great, but non-trivial stuff (I've done stuff far heavier than in the quoted post) it occasionally causes issues. This is most common when it uses other components or GameObjects, and tends to come up at load time rather than when editing.

    Still incredibly useful in general, but... we'll, I did call it "abusing" in the quoted post. ;)
     
  31. LucasHehir

    LucasHehir

    Joined:
    May 7, 2020
    Posts:
    74
    I've noticed recently that in a setter invoked from OnValidate (like the examples outlined above) the private field and value will already be the same value now even before you've assigned it. How strange! I swear the private field used to contain the pre-assignment value. It was great for doing things like logging "This value is changing from [{A}] to [{B}]" for debugging.
     
  32. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,006
    What exactly has this to do with C# properties and get / set method of said properties? Really, you're not adding anything to the discussion about getter, setter or the relationship of the inspector. You seem to have a concrete issue in your concrete project. Create a seperate thread with a descriptive title and add more information on your actual issue. Because "everything is working" and "then broken" could apply to to literally anything.

    Don't hijack other threads with other topics.
     
  33. PanthenEye

    PanthenEye

    Joined:
    Oct 14, 2013
    Posts:
    2,079
    Code (CSharp):
    1. [field: SerializeField] public GameObject myObj { get; private set; }
    This is a thing now too if anyone's seeking solutions to the problem in the OP and can get away with auto property.
     
    Rowan_Kim, petey, havokentity and 3 others like this.
  34. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,006
  35. ScionGlobe

    ScionGlobe

    Joined:
    Oct 28, 2020
    Posts:
    3
    Thank you, I've used this before but couldn't remember the syntax...