Search Unity

SetGet Confusion.

Discussion in 'Scripting' started by DeeJayVee, Jun 26, 2019.

  1. DeeJayVee

    DeeJayVee

    Joined:
    Jan 2, 2015
    Posts:
    121
    Hi.

    I think I'm confused with SetGetters, I have a BaseStat class which has a baseValue a currentValue and an extra BaseStat class called statAdditive.

    my currentValuers SetGetter looks like this;

    Code (CSharp):
    1. public float CurrentValue
    2.     {
    3.        
    4.         get
    5.         {
    6.             if (statAdditive != null)
    7.             {
    8.                 return (baseValue + currentValue) + StatAdditive.CurrentValue;
    9.  
    10.             }
    11.             else
    12.                 return baseValue + currentValue;
    13.  
    14.  
    15.  
    16.         }
    17.         set { currentValue = value; }
    18.        
    19.     }
    I also have a testing script just to visualize all of my values, it is setup like this;

    Code (CSharp):
    1. void Update () {
    2.  
    3.         healthText.text = ("Health (" + currentActor.Health.CurrentValue.ToString()) + ")";
    4.         Debug.Log(currentActor.Health.CurrentValue + currentActor.Health.StatAdditive.CurrentValue);
    5.        
    6.         manaText.text = ("Mana (" + currentActor.Mana.CurrentValue.ToString()) + ")";
    7.  
    8.         attackPowerText.text = ("AttackPower (" + currentActor.AttackPower.CurrentValue.ToString()) + ")";
    9.  
    10.         strengthText.text = ("Strength (" + currentActor.Strength.CurrentValue.ToString()) + ")";
    11.         mindText.text = ("Mind (" + currentActor.Mind.CurrentValue.ToString()) + ")";
    12.  
    13.         luckText.text = ("Luck (" + currentActor.Luck.CurrentValue.ToString()) + ")";
    14.     }
    15. }
    As well as a basePlayer class where I've just set up some BaseStat classes and their respective Setgetters.
    At the moment, it's a little messy because I've been testing, but currently my Start and Update look like this ;

    Code (CSharp):
    1.     void Start () {
    2.         Health.StatAdditive = Strength;
    3.         Mana.StatAdditive = Mind;
    4.  
    5.         Health.BaseValue = 100;
    6.         Mana.BaseValue = 10;
    7.         Strength.CurrentValue = 10;
    8.     }
    9.    
    10.    
    11.     void Update () {
    12.        
    13.         if (Input.GetMouseButtonDown(0)){
    14.             Debug.Log(Health.StatAdditive.CurrentValue);
    15.        
    16.         }
    17.     }
    18.  

    My problem is, my test script will only display the baseStat current value without it's StatAdditive currentValue which made me think that StatAdditive is null but when I use the Debug line I can see that it has a StatAdditive and if I try to get the StatAdditives currentValue i can reach it, so it is there.

    I believe it is because I don't understand Setgetters properly, but why does this not work?
     
  2. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,196
    First, I don't know if this is the issue, but in that code sample you've for 'statAdditive' as well as 'StatAdditive' in the getter. Are those the same? Or is that typo perhaps the problem?

    Next, the get/set approach you're using here seems flawed for one specific reason: If I set CurrentValue to "x", and then ask for CurrentValue, I won't necessarily get "x". For example,

    Code (CSharp):
    1. MyObj.CurrentValue = 5;
    2. if (MyObj.CurrentValue == 5) {
    3.     // Looking at this code, you'd probably assume this condition would always be true.
    4.     // However, the CurrentValue getter will actually return the sum of the "5" I just
    5.     // set, along with the baseValue, and maybe the statAdditive. So, there are lots of
    6.     // reasons why we might never hit this code.
    7. }
    I don't know if there's a design principle that specifically states that the getter should always return the value you just assigned to the setter, but that feels like the reasonable approach.
     
  3. DeeJayVee

    DeeJayVee

    Joined:
    Jan 2, 2015
    Posts:
    121
    The StatAdditive SetGetter has a private variable statAdditive, I have changed that to be more formal, but that wasn't the issue.

    In the Setgetter, outside of the if statement, I can say "return (any number)" and it will show that number, basically, it's skipping the if statement and acting as if statAdditive is null which my debug logs prove otherwise. I know if statements work in Setgetters, which is why I'm confused.
     
  4. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,196
    Well, not that this will change anything, but you can simplify your getter to just this:

    Code (CSharp):
    1. get { return baseValue + currentValue + StatAdditive?.CurrentValue; }
    The "?" means that it will evaluate property as long as the object isn't null. This can be handy to avoid long strings of null checks. For example, A?.B?.C?.D would give you "D" as long as A, B, and C are all not null.

    Anyway, as to your issue, nothing really comes to mind. The code you've shown should work. Sure there are no compiler errors? Maybe you can add this to your getter:

    Code (CSharp):
    1. Debug.Log($"baseValue: {baseValue}; currentValue: {currentValue}; Additive: {StatAdditive?.CurrentValue;}");
    Put that at the beginning, which should provide complete proof of the values involved. I'd have to assume that StatAdditive.CurrentValue just doesn't have the value you think it does. Maybe Strength and Mind don't have the correct values when Start is run, because their values are populated until later?
     
  5. DeeJayVee

    DeeJayVee

    Joined:
    Jan 2, 2015
    Posts:
    121
    With that code I get a "Cannot convert type float? to float" are you missing a cast" error.

    but for the Debug code, for the Health it returns;

    Code (CSharp):
    1. baseValue: 100; currentValue 0; Additive: 10
    So, it works, Health should show 110. Very confusing.
     
    Last edited: Jun 26, 2019
  6. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,196
    Well, I'm not sure what's causing you to get the wrong value. Maybe it's something simpler, like the script is on two objects, and you're looking at the wrong one, or some mixup like that. The code itself works fine. I tested it out:

    Code (CSharp):
    1. class StatAdd
    2.         {
    3.             public float CurrentValue;
    4.         }
    5.         private StatAdd statAdditive;
    6.         private float baseValue;
    7.         private float currentValue;
    8.  
    9.         public float CurrentValue
    10.         {
    11.  
    12.             get
    13.             {
    14.                 Debug.Log($"Getting CurrentValue, composed of {baseValue}, {currentValue}, and {statAdditive?.CurrentValue}");
    15.                 if (statAdditive != null)
    16.                 {
    17.                     return (baseValue + currentValue) + statAdditive.CurrentValue;
    18.  
    19.                 }
    20.                 else
    21.                 {
    22.                     return baseValue + currentValue;
    23.                 }
    24.             }
    25.             set { currentValue = value; }
    26.         }
    27.  
    28. void Start()
    29.         {
    30.             statAdditive = new StatAdd();
    31.             CurrentValue = 2;
    32. }
    33.  
    34.  
    35.  
    36. void Update()
    37.         {
    38.  
    39.             if (Input.GetKeyDown(KeyCode.J))
    40.             {
    41.                 statAdditive.CurrentValue += 2;
    42.                 Debug.Log($"Added two to statAdditive.CurrentValue, bringing total to {CurrentValue}");
    43.             }
    44.             if (Input.GetKeyDown(KeyCode.K))
    45.             {
    46.                 CurrentValue = Time.time;
    47.                 Debug.Log($"Set current to {Time.time}, bringing total to {CurrentValue}");
    48.             }
    49.             if (Input.GetKeyDown(KeyCode.L))
    50.             {
    51.                 Debug.Log($"CV is {CurrentValue}");
    52.             }
    53. }
    That produced completely expected values when pressing J/K/L to manipulate the numbers. Can you put this on a single object in a test scene, and see if it works there, just to make sure this is the result of some other script, or multiple instances of a script?
     
  7. DeeJayVee

    DeeJayVee

    Joined:
    Jan 2, 2015
    Posts:
    121
    Ok, so I knew I didn't have multiples and I double checked the code. And it turns out you were right the first time. statAdditive and Statadditive, were wrong, I needed to check if StatAdditive was null. I did formalize it but used the private variable, which means I did need to learn about Setgetters just not the way I thought.

    Thank you very much for your continued help, it is fixed now, and have learned a few more things.
    While I have you here though, how did you learn to use Debug with these values;

    Code (CSharp):
    1. Debug.Log($"Getting CurrentValue, composed of {baseValue}, {currentValue}, and {statAdditive?.CurrentValue}");
    Where can I learn things like this? It's very useful.
     
  8. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,196
    I'm not sure exactly how you mean you question. I'm not sure if you're asking:
    • The use of the $ in the Debug.Log? If so, that's called String Interpolation in C#.
    • Using Debug.Log in general for debugging code? (It seems you already knew how to do that, so that's probably not your question.)
    • How did I just generally learn little details about how to do things in C#? Mainly from having been using it for 10+ years in my job. But one really useful way to distill some nice features of C# is to actually look at pages like "What's new in C# 6?", "What's new in C# 7?", basically the release notes for C#. It tends to show very useful new functionality that I use a lot. Also, if you do the same thing over and over, often you'll get annoyed if the operation is tedious, and it will inspire you to look up a different approach to doing things, and then you'll learn.
    If I missed the point of your question, please let me know and rephrase it. :)