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

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!

public class PlayerScript : MonoBehaviour
{

    [SerializeField]
    public int starJumps;

// GameObjects below are the sprites for each jump icon
    [SerializeField]
    public GameObject oneStarJump;

    [SerializeField]
    public GameObject twoStarJump;
    [SerializeField]
    public GameObject threeStarJump;
    [SerializeField]
    public GameObject fourStarJump;
    [SerializeField]
    public GameObject fiveStarJump;
    [SerializeField]
    public GameObject sixStarJump;
   

void Update()
{
if (starJumps <= 0)
        {
            oneStarJump.SetActive(false);
            twoStarJump.SetActive(false);
            threeStarJump.SetActive(false);
            fourStarJump.SetActive(false);
            fiveStarJump.SetActive(false);
            sixStarJump.SetActive(false);
        }
        else if (starJumps == 1)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(false);
            threeStarJump.SetActive(false);
            fourStarJump.SetActive(false);
            fiveStarJump.SetActive(false);
            sixStarJump.SetActive(false);
        }
       
        else if (starJumps == 2)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(true);
            threeStarJump.SetActive(false);
            fourStarJump.SetActive(false);
            fiveStarJump.SetActive(false);
            sixStarJump.SetActive(false);
        }
       
        else if (starJumps == 3)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(true);
            threeStarJump.SetActive(true);
            fourStarJump.SetActive(false);
            fiveStarJump.SetActive(false);
            sixStarJump.SetActive(false);
        }
       
        else if (starJumps == 4)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(true);
            threeStarJump.SetActive(true);
            fourStarJump.SetActive(true);
            fiveStarJump.SetActive(false);
            sixStarJump.SetActive(false);
        }
       
        else if (starJumps == 5)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(true);
            threeStarJump.SetActive(true);
            fourStarJump.SetActive(true);
            fiveStarJump.SetActive(true);
            sixStarJump.SetActive(false);
        }
        else if (starJumps >= 6)
        {
            oneStarJump.SetActive(true);
            twoStarJump.SetActive(true);
            threeStarJump.SetActive(true);
            fourStarJump.SetActive(true);
            fiveStarJump.SetActive(true);
            sixStarJump.SetActive(true);
        }
}

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.

Thank you for the quick reply! I’m going to try and figure that out using that approach. Thanks so much :smile:

Just because I’m bored while waiting for something to process at work, here’s the general idea:

public class PlayerScript : MonoBehaviour
{
    [SerializeField]
    private int _starJumpsAmount;
  
    [SerializeField]
    private List<GameObject> _startJumpIcons;
  
    public void SetStarJumps(int jumpAmount)
    {
        if (jumpAmount < 0 || jumpAmount >= _startJumpIcons.Count)
        {
            // warn user of invalid number
            return;
        }
      
        _starJumpsAmount = jumpAmount;
      
        int count = _startJumpIcons.Count;
        for (int i = 0; i < count; i++)
        {
            bool active = (i < _starJumpsAmount);
            var icon = _startJumpIcons[i];
            icon.SetActive(active);
        }
    }
}

My fellow for-loop list.Count hoister!

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! :smile:

“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.

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

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.

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.

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?

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.

If anyone is curious on this matter I found an article by Jackson Dunstan on it:

NOTE: If you count backward then you dont need to cache it
Do all my loops are like

for ( int i=list.Count-1; i>=0; i--)
{

}

I get you zedz, and I do appreciate your intent. I grew up with the DJNZ instruction too. :slight_smile:

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:

int count = myList.Count;

while( count-- > 0)
{
  Debug.Log( myList[count]);
}

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! :slight_smile:

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

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’