If Object In List Is Missing Check In Unity C+

I have been searching everywhere for an answer and I can’t find one that works, so somebody please help me. I am trying to make it so every time an XP slider bar gets filled up all the way, then 3 random upgrade buttons will pop up and you can select them. After the player selects them then the button for that option gets destroyed and goes missing from the script. Every time the XP bar gets full, a random number generator is activated 3 times to randomly choose 3 upgrades. What I want it to do is ignore or skip over the objects that go missing because the player already picked that upgrade, and randomly find a new upgrade.

Here is the code I tried using for if the upgrade was already chosen/missing:

if (Options[CurrentOptionIndex].gameObject == null)
        {
            RandomOptionNumber = Random.Range(1, 5);
            Debug.Log(" List Object was null");
        }

Here’s the code when it selects a random number (I know its repetitive and there is probably a better way to do it):

if (script2.NewUpgradeSelection)
        {
            if (i < 3)
            {
                RandomOptionNumber = Random.Range(1, 5);
                i++;
            }

            if (i >= 3)
            {
                script2.NewUpgradeSelection = false;
            }

        }

        if (RandomOptionNumber == 1)
        {
            CurrentOptionIndex = 1 % Options.Count;
            Options[CurrentOptionIndex].SetActive(true);
            RandomOptionNumber = 0;
        }

        if (RandomOptionNumber == 2)
        {
            CurrentOptionIndex = 2 % Options.Count;
            Options[CurrentOptionIndex].SetActive(true);
            RandomOptionNumber = 0;
        }

        if (RandomOptionNumber == 3)
        {
            CurrentOptionIndex = 3 % Options.Count;
            Options[CurrentOptionIndex].SetActive(true);
            RandomOptionNumber = 0;
        }

        if (RandomOptionNumber == 4)
        {
            CurrentOptionIndex = 4 % Options.Count;
            Options[CurrentOptionIndex].SetActive(true);
            RandomOptionNumber = 0;
        }

        if (RandomOptionNumber == 5)
        {
            CurrentOptionIndex = 5 % Options.Count;
            Options[CurrentOptionIndex].SetActive(true);
            RandomOptionNumber = 0;
        }

Here is the code for listing it in the inspector:

[SerializeField] private List<GameObject> Options = new List<GameObject>();

public int i;
    public int RandomOptionNumber;
    public int CurrentOptionIndex;

I AM A BEGINNER!

When the play choses the option, not only do you want to destroy it, but you want to Remove() it from the list as well. That way you don’t have a bunch of missing references polluting the collection.

Yes, true, but if I remove them, then the CurrentOptionIndex for the options will be messed up, because if lets say option 2 is CurrentOptionIndex number 2, then I choose another option and that other option gets removed, then it will mess with the order and option 2 won’t be CurrentOptionIndex 2 anymore.

Well to that end, you don’t want to hard code what every number does. You’ll want to generate numbers tied to the size of the collection.

Firstly, important to note that when Random.Range for integers, the max value is exclusive. So currently in your code, 5 will never actually be generated. Also collection indexes start at 0, so if you want to include all options, you want to use Random.Range(0, collection.Length/Count);

In the most basic sense you can do:

for (int i = 0; i < 3; i++)
{
    int optionIndex = Random.Range(0, Options.Count);
    var option = Options[optionIndex];
   
    option.SetActive(true);
}

To get three random options, though this doesn’t account for getting the same number twice, but mostly trying to illustrate an idea here.

Then when the player picks an option, you can both destroy it, and remove it from the collection.

So could you give example code of how I would make it so the integers are not hard coded.

I already did?

Oh sry, then to make it so that the randomizer doesn’t pick a option that has already been randomly picked, do I do this?

if (!Options[CurrentOptionIndex].gameObject.activeSelf)
        {
            RandomOptionNumber = Random.Range(0, Options.Count);
            Debug.Log("Option Already Active");
        }

Which I’m trying to get it to say if the option is active already than pick a different number.

Follow up question, do you know how to remove the item that the player chooses from the list.

Then just do the check in the for-loop. You may have to make it do another iteration of the loop, or perhaps a loop within a loop.

Off the cuff code:

for (int i = 0; i < 3; i++)
{
    GameObject option;
   
    do
    {
        int optionIndex = Random.Range(0, Options.Count);
        option = Options[optionIndex];
    }
    while (option.ActiveSelf() == true)
   
    option.SetActive(true);
}

Ergo, keep looping until we hit a game object that is not active.

Though your code will want to have some sanity checks. Such as if there’s only three or less options left, just make those all active.

You may want to look at ways to generate random, different numbers. Do some googling. No doubt this topic has been covered in the past.

So again, if you didn’t see the last post, how do would you remove the option that the player chooses, because it isn’t a hard coded number anymore.

Listen for the option the player chooses, and remove that from the list. It’s a UI element right? A button perhaps? Register a method with it’s click callback and use that to remove the respective button. You probably want a custom component on these options with a delegate to subscribe to.

If you don’t know how, then do some reading up on that. Can’t write every bit of code for you.

I have a custom void that runs when the player selects the item he wants, but then I am still confused on how I would get that specific button the player chose to be removed from the list. Yes they are button UI elements.

Think of this problem like it’s a deck of cards. You add a few cards to a pile: 1 2 3 4 5. You pick a card at random (say, the third one, which is 3) and remove it from the pile. The pile now contains 1 2 4 5. You pick another card at random from the remaining pile (say the third one again, which is now 4) and remove it from the pile.

List<Thing> listOfChoices;
listOfChoices.Add(new Thing(1)); // and so on
//...
int chosen = Random.Range(0, listOfChoices.Count);
Thing choice = listOfChoices[chosen];
listOfChoices.RemoveAt(chosen);

The things you put into the list of choices should have all the information you need for your purposes. Maybe each “card” or Thing in the list of choices is a reference to a Button, so use List<Button> listOfChoices;

You really don’t want to organize any “pick a remaining item” routine as a nested loop which repeats until it finds one. First, that’s an unpredictable amount of wasted time, like throwing darts until you hit a red spot. Second, it invites an infinite loop hang/crash if you accidentally try to pick from a set of choices that has nothing remaining.

Yes, but the problem is that I have it so after the player presses the option it gets removed, that’s what I want. The randomizer goes and picks options before the player picks them, so if I were to say this then the 3rd option that was randomly picked will be removed every time, not the option that the player picked because the int chosen would be the last randomly picked int/option.

Then like I said, do some learning into delegates and how to pass parameters through them.

This brings me back to my question on if it would be possible to find an option that is null or missing in the list, and then remove it, which will make the level-up system work.

Sure, just iterate through the list and remove any elements that are null. Usually you want to run through the list backwards when doing this.

Could you give me an example code on how to check if there is a null and remove it, I have looked in so many places trying to find an answer which made me come here. PLEASE HELP AGAIN.

Like I said. Just run through the list backwards, check if an element is null, and remove it if it is.

for (int i = Options.Count - 1; i > -1; i--)
{
    if (Options[i] == null)
    {
        Options.RemoveAt(i);
    }
}

Ok so, I think I did this, but I don’t think it is running the removeAt null, and unity crashed unity when I ran it, so did I do it right? I think it is just the part where I’m checking for null that’s not working.

It is in Update Function:

if (script2.NewUpgradeSelection)
        {

            GameObject option;

            if (i < 3)
            {
                do
                {
                    CurrentOptionIndex = Random.Range(0, Options.Count);
                    option = Options[CurrentOptionIndex];
                }
                while (option.activeSelf == true);

                option.SetActive(true);
                i++;
            }

            if (i >= 3)
            {
                script2.NewUpgradeSelection = false;
            }

        }

        int removeNull = Options.Count - 1;

        if (removeNull > -1)
        {
            if (Options[removeNull] == null)
            {
                Options.RemoveAt(removeNull);
                Debug.Log("Removed Options That Were Null");
            }
            i--;
        }