Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question What's a cleaner way to disable/enable UI icons with code then checking and writing for each UI code

Discussion in 'Scripting' started by antonioniii, Sep 1, 2023.

  1. antonioniii

    antonioniii

    Joined:
    Jun 15, 2020
    Posts:
    24
    In my game you have 6 jumps. Each jump is represented by an icon.

    When you have 6 jumps, we show 6 icons in the UI. When you have 5 jumps, you see 5 jump icons. Etc.

    Rather than this primitive mess I did after not coding for 2-3 months, what is a more elegant and cleaner way to do this? I feel like there is a nice for loop that could do this? Thank you in advance!

    Code (CSharp):
    1. public class PlayerScript : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField]
    5.     public int starJumps;
    6.  
    7. // GameObjects below are the sprites for each jump icon
    8.     [SerializeField]
    9.     public GameObject oneStarJump;
    10.  
    11.     [SerializeField]
    12.     public GameObject twoStarJump;
    13.     [SerializeField]
    14.     public GameObject threeStarJump;
    15.     [SerializeField]
    16.     public GameObject fourStarJump;
    17.     [SerializeField]
    18.     public GameObject fiveStarJump;
    19.     [SerializeField]
    20.     public GameObject sixStarJump;
    21.    
    22.  
    23. void Update()
    24. {
    25. if (starJumps <= 0)
    26.         {
    27.             oneStarJump.SetActive(false);
    28.             twoStarJump.SetActive(false);
    29.             threeStarJump.SetActive(false);
    30.             fourStarJump.SetActive(false);
    31.             fiveStarJump.SetActive(false);
    32.             sixStarJump.SetActive(false);
    33.         }
    34.         else if (starJumps == 1)
    35.         {
    36.             oneStarJump.SetActive(true);
    37.             twoStarJump.SetActive(false);
    38.             threeStarJump.SetActive(false);
    39.             fourStarJump.SetActive(false);
    40.             fiveStarJump.SetActive(false);
    41.             sixStarJump.SetActive(false);
    42.         }
    43.        
    44.         else if (starJumps == 2)
    45.         {
    46.             oneStarJump.SetActive(true);
    47.             twoStarJump.SetActive(true);
    48.             threeStarJump.SetActive(false);
    49.             fourStarJump.SetActive(false);
    50.             fiveStarJump.SetActive(false);
    51.             sixStarJump.SetActive(false);
    52.         }
    53.        
    54.         else if (starJumps == 3)
    55.         {
    56.             oneStarJump.SetActive(true);
    57.             twoStarJump.SetActive(true);
    58.             threeStarJump.SetActive(true);
    59.             fourStarJump.SetActive(false);
    60.             fiveStarJump.SetActive(false);
    61.             sixStarJump.SetActive(false);
    62.         }
    63.        
    64.         else if (starJumps == 4)
    65.         {
    66.             oneStarJump.SetActive(true);
    67.             twoStarJump.SetActive(true);
    68.             threeStarJump.SetActive(true);
    69.             fourStarJump.SetActive(true);
    70.             fiveStarJump.SetActive(false);
    71.             sixStarJump.SetActive(false);
    72.         }
    73.        
    74.         else if (starJumps == 5)
    75.         {
    76.             oneStarJump.SetActive(true);
    77.             twoStarJump.SetActive(true);
    78.             threeStarJump.SetActive(true);
    79.             fourStarJump.SetActive(true);
    80.             fiveStarJump.SetActive(true);
    81.             sixStarJump.SetActive(false);
    82.         }
    83.         else if (starJumps >= 6)
    84.         {
    85.             oneStarJump.SetActive(true);
    86.             twoStarJump.SetActive(true);
    87.             threeStarJump.SetActive(true);
    88.             fourStarJump.SetActive(true);
    89.             fiveStarJump.SetActive(true);
    90.             sixStarJump.SetActive(true);
    91.         }
    92. }
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    The answer would just be to use an array/list to reference these stars. Loop through the collection and enable the first n stars equal to
    startJumps
    , then disable each star after that.

    Definitely doesn't need to be in an update loop. Make the field private, and have a public method that changes the value of
    startJumps
    , and updates the currently displayed stars.
     
    antonioniii likes this.
  3. antonioniii

    antonioniii

    Joined:
    Jun 15, 2020
    Posts:
    24
    Thank you for the quick reply! I'm going to try and figure that out using that approach. Thanks so much :D
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Just because I'm bored while waiting for something to process at work, here's the general idea:

    Code (CSharp):
    1. public class PlayerScript : MonoBehaviour
    2. {
    3.     [SerializeField]
    4.     private int _starJumpsAmount;
    5.  
    6.     [SerializeField]
    7.     private List<GameObject> _startJumpIcons;
    8.  
    9.     public void SetStarJumps(int jumpAmount)
    10.     {
    11.         if (jumpAmount < 0 || jumpAmount >= _startJumpIcons.Count)
    12.         {
    13.             // warn user of invalid number
    14.             return;
    15.         }
    16.      
    17.         _starJumpsAmount = jumpAmount;
    18.      
    19.         int count = _startJumpIcons.Count;
    20.         for (int i = 0; i < count; i++)
    21.         {
    22.             bool active = (i < _starJumpsAmount);
    23.             var icon = _startJumpIcons[i];
    24.             icon.SetActive(active);
    25.         }
    26.     }
    27. }
     
    Last edited: Sep 1, 2023
    CodeRonnie and antonioniii like this.
  5. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    My fellow for-loop list.Count hoister!
     
  6. antonioniii

    antonioniii

    Joined:
    Jun 15, 2020
    Posts:
    24
    Haha! Wow. You're amazing. Thank you!
    So clever and cool! Thank you so much for writing this out. Incorporating it now after parsing and understanding it. Very appreciative! :D
     
    spiney199 likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    "One thing per line please!"

    I love it too.

    I think I just would have put lines 19 to 25 in a block to contain the scope of
    count
    but I'm funny that way. I remember working with a Java engineer circa 2007 who saw me doing these sub-blocks and called it "crack cocaine programming" and I never really understood what he meant by that, but he disliked sub-blocks in code except when necessary.
     
    antonioniii likes this.
  8. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    Mind officially blown... I've never seen that done before.. I've always heard they're technical bools in if statements, but now know they just are bools..

    The Lebowski meme is playing in my head right now, but instead of "money" it's "if statements"... lmao
     
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    I've written enough code that runs through very large collections where avoiding the repeated method calls to
    .Count
    makes a noticeable performance improvement, so it's become a habit.
     
    wideeyenow_unity likes this.
  10. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    839
    I used to hoist all of the time for the same reason. I assumed it was faster based on experiences from long long ago. However, recently I was looking into to micro optimizations due to the fact that I had to iterate over lists of millions of items and it turns out that in some cases this can really hurt performance and not by an unmeasureable amount! Basically, the newer compilers are smart enough that in some cases they can see the reference to the length of the list and infer that the array being accessed cannot possibly ever have an out-of-bounds due to the looping so they don't generate the checks for that. Using a local variable will actually cause this inference to never be made. Complex referencing of array elements can also disable this behavior though too. So generally, it doesn't happen in all cases but in very simple and tight loops it almost always seems to work and the performance gained for such light loops that are iterating a lot (like, a lot alot) it really can have a big impact.

    Anyway, just my two cents on something that is very situational and rarely needs to actually be considered in your average daily coding adventures.
     
  11. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    This also made me think of if the list was being modified in some way, if you pre-declare the count, then it will cause errors because that number couldn't change while the for loop is running. But again, that's just situational(case by case)..

    Although, thinking on it logically, wouldn't just having a temporary cached number, to check against, be faster than calling the list component to get .Count? Unless it uses some internal logic, basically on the C++ side, and not having to revert back to C# side, then back again.. Interesting, never thought of it that way, so maybe?
     
  12. Sluggy

    Sluggy

    Joined:
    Nov 27, 2012
    Posts:
    839
    Well I should stress that in my case it was entirely C# code with nothing referencing Unity's API so there was no marshalling going on. It was also a case where the looping mechanics were as heavy as the logic itself. In either case it's more-or-less totally irrelevant to the OP's question. It would simply never be a concern for such a simple case.
     
  13. wideeyenow_unity

    wideeyenow_unity

    Joined:
    Oct 7, 2020
    Posts:
    728
    If anyone is curious on this matter I found an article by Jackson Dunstan on it:
    https://www.jacksondunstan.com/articles/3577
     
    Sluggy likes this.
  14. zedz

    zedz

    Joined:
    Aug 31, 2013
    Posts:
    229
    NOTE: If you count backward then you dont need to cache it
    Do all my loops are like

    Code (CSharp):
    1. for ( int i=list.Count-1; i>=0; i--)
    2. {
    3.  
    4. }
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    I get you zedz, and I do appreciate your intent. I grew up with the DJNZ instruction too. :)

    But I find the above structure difficult because of the two opportunities for OBOB (off-by-one-bug):

    - one is at the start count being off by one
    - one is at the end test being
    >= 0
    rather than a pure
    > 0


    Whenever I feel the need to DJNZ in C-like code it's always as a pure post-decremented counter:

    Code (csharp):
    1. int count = myList.Count;
    2.  
    3. while( count-- > 0)
    4. {
    5.   Debug.Log( myList[count]);
    6. }
    Same outcome, just smaller error surface to me.

    It has the side benefit of leaving
    count == -1
    afterwards, which will blow up if you attempt to use it to dereference any collection beyond the loop. Nice!!

    (And of course back in C / C++ I was lazy and did
    while( count--)
    because everything could be "booleaned" that way.)

    But hey, if you're used to getting over those two OBOB opportunities, you do you! :)

    Still though, mostly these days I start from
    i = 0
    and go up with the
    i < count
    check.

    Fun fact: many DJNZ instructions I wrote in high school are still running today in my KurtMaster2D collection of games, several of which are emulated Z-80 byte code running inside of Unity3D!

    Apple iTunes: https://itunes.apple.com/us/app/kurtmaster2d/id1015692678
    Google Play (including TV): https://play.google.com/store/apps/details?id=com.plbm.plbm1
    Itch.io: https://kurtdekker.itch.io/kurtmaster2d
     
    Last edited: Sep 3, 2023
  16. zedz

    zedz

    Joined:
    Aug 31, 2013
    Posts:
    229
    Ha I used to code Z80 ASM too back in the 80s as a kid, can't remember much, though saw the number 209 the other day and automatically translated it to C9 = ret;

    I see one of your games is nearly called the same as one of mine, 'Rocket Raiders TV'
    https://store.steampowered.com/app/2421640/Retro_Rocket_Raiders/
     
    Kurt-Dekker likes this.