Search Unity

Set value using property or method

Discussion in 'Scripting' started by LazyBird, Aug 1, 2020.

  1. LazyBird

    LazyBird

    Joined:
    Mar 30, 2020
    Posts:
    30
    I'm working on a tower defense game at the moment and have realized that I'm not really following any standard approach when it comes to updating the values of fields between classes, which I don't like. For example, I have a build manager singleton which is being used to hold information on what tower has been selected in the UI, and when an available space on the game grid is clicked then that tower is built.

    Currently, I'm using a public GameObject named TowerToBuild inside a BuildManager class to hold this data. At the beginning of the game, the BuildManager class assigns a default standard tower to this variable.

    When updating a value like this from another class, the UIManager for example, is it best to:

    A. Keep the variable public (or property with public set method) and update the value directly by accessing BuildManager.Instance.TowerToBuild and assigning the new tower to it.
    B. Add an UpdateTowerToBuild() method to the BuildManager class which accepts the GameObject as a parameter and update it by calling this method.

    It seems I've been doing a bit of both over the past few months, depending on things I've read or tutorials I've taken and I'd much prefer to have a standard approach. Also, I know that option B would allow for additional logic to be built inside the method which we may want to live inside the BuildManager class itself. Including this logic as part of a property would also work here of course, and my research on property usage so far has given me an insight in to how shorter, simpler pieces of logic generally should exist in properties and more complex pieces inside methods. I feel like I have an ok understanding of this. I'm more interested in the very simple use case above, where we're just updating a field. Are they both exactly the same? Just a design choice? Do you use both options or try to stick to one for consistency? Feedback much appreciated!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    Public variables are generally frowned upon. It's considered allowing access to the internal state of the class, which is discouraged in object oriented programming.

    For simply updating a field from outside the class, a property is generally preferred. It's concise, well understood by c# developers, and allows for the class to fully control access to its own data. If necessary it will be seamless later to add custom getter/setter without changing any other code.
     
    LazyBird likes this.
  3. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    That's the major reason to use a function. You feel like an idiot writing a pass-through like
    public setTowerType(Tower t) { this.t=t; }
    , but there's almost always something else that eventually needs to be done. Pretty soon you've got 4 places in your code each running an identical 6 lines to add a tower; and you've got that for everything else and it's all a huge pain. For real, that happens maybe 1 time in 4, but writing out a function it's still worth it.
     
    Last edited: Aug 2, 2020
  4. LazyBird

    LazyBird

    Joined:
    Mar 30, 2020
    Posts:
    30
    Thanks guys. So would the optimal base approach be to use a property if it's ONLY the value I want to update with no additional logic attached. If I have some light additional logic to include that inside the setter method. And if, like Owen-Reynolds alluded to above, had a larger piece of code to include then to make it a method. I know there's an element of preference here, but would like to get some feedback on whether that approach would be considered modular and scale-able. Of course my goal is always to have the tidiest code possible with no unnecessary repeating.
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,911
    There's definitely an element of preference to it.

    I actually use properties all the time when there's more than just setting the simple value involved. Especially when there's an event involved, or when I'm trying to abstract a complicated process to a single variable. For example here's a property I wrote for enabling and disabling "bullet time" slow motion in one of my projects. The caller can just set bullet time on or off, but under the hood it's setting two other values (unity's time steps) as well as firing off an event.

    Code (CSharp):
    1.     bool _isInBulletTime = false;
    2.     public bool BulletTime {
    3.         get => _isInBulletTime;
    4.         set {
    5.             if (value == _isInBulletTime) return;
    6.  
    7.             _isInBulletTime = value;
    8.             if (value) {
    9.                 Time.timeScale = BulletTimeTimeScale;
    10.                 Time.fixedDeltaTime = normalFixedTimestep * BulletTimeTimeScale;
    11.             }
    12.             else {
    13.                 Time.timeScale = 1f;
    14.                 Time.fixedDeltaTime = normalFixedTimestep;
    15.             }
    16.             OnBulletTime?.Invoke(this, value);
    17.         }
    18.     }
     
  6. LazyBird

    LazyBird

    Joined:
    Mar 30, 2020
    Posts:
    30
    Great to see an example like that, thanks PraetorBlue!
     
  7. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    bulletTime could be functions. The inside would be the same (obviously). The functions might start as:
    Code (CSharp):
    1. void beginBulletTime() { ...
    2. void endBulletTime() { ...
    3. bool isInBulletTime() { ...
    The last one seems awkward, but how often do you check on/off? The first two are longer, but
    beginBulletTime();
    might be more obvious than
    bulletTime=true;
    . Then suppose bullet-time gets has a blue overlay, and a countdown... . To most people a function communicates "this might do lots of stuff" (which is what the "keep properties small" advice also says. ='s doing lots of extra work confuses people). Then suppose you can't always enter bullet time and want to return whether it worked:
    Code (CSharp):
    1. bool attemptToBeginBulletTime() { ...
    2. // true means it worked
    Maybe items can send you into it bypassing the normal cost:
    Code (CSharp):
    1. bool attemptToEnterBulletTime(bool alwaysWorks=false, float bonusSeconds=5.0f) { ...
    2.  
    3. // sample of use:
    4. // use the scroll as a back-up if we can't enter normally:
    5. if(attemptToEnterBulletTime()==false) {
    6.   attemptToEnterBulletTime(true, scroll.power)
    7.     Destroy(scroll);
    8. }
    9.  
    As a property it would be the funny:
    bulletTime=true; if(bulletTime==false)
    .

    This seems made-up, but I often have simple get/set functions grow in weird ways like this. It's about planning. You never know how big something will get. But if you suspect it might grow, becoming big enough or needing with 2+ parameters, might as well start it as a function.