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.
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);
}
}
}
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.
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.
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!
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’