How would I select GameObjects from a List in a Dropdown Menu?

I’m trying to populate dropdown menus from lists of GameObjects, and then select those game objects by their index.

So, the population of the dropdowns works just fine. However, the selection does not. I wind up with, from the first list, many, many gameobject.name instances in the console. And from others, an exception message: Argument out of Range exception. Index was out of range. Must be non-negative and less than the size of the collection.

Here is the relevant snipped of my code:

public List list_TacticalTargetTypeSelector = new List() { "Allied Starships", "Hostile Starships", "Allied Starbases", "Hostile Starbases", "Asteroids" };

public string tacTargetType;

public TMP_Dropdown dropDown_TMP_TacticalTargetSelector;

public void addGamePiecesToTacticalTargetSelectorDropDownMenu()
    {

        if (tacTargetType == "Allied Starships")
        {

            dropDown_TMP_TacticalTargetSelector.ClearOptions();
            dropDown_TMP_TacticalTargetSelector.AddOptions(listManagerGlobal.list_AlliedStarships.ConvertAll(alliedStarships => alliedStarships.name));

        }

        else if (tacTargetType == "Hostile Starships")
        {

            dropDown_TMP_TacticalTargetSelector.ClearOptions();
            dropDown_TMP_TacticalTargetSelector.AddOptions(listManagerGlobal.list_HostileStarships.ConvertAll(hostileStarships => hostileStarships.name));

        }

[etc., etc...]

    }

    public void selectGamePieceFromTacticalTargetSelectorDropdown()
    {

        if (tacTargetType == "Allied Starships")
        {

            dropDown_TMP_TacticalTargetSelector.onValueChanged.AddListener(index => Debug.Log(listManagerGlobal.list_AlliedStarships[index]));

        }

        else if (tacTargetType == "Hostile Starships")
        {

            dropDown_TMP_TacticalTargetSelector.onValueChanged.AddListener(index => Debug.Log(listManagerGlobal.list_HostileStarships[index]));

        }

[etc., etc....]

    }

addGamePiecesToTacticalTargetSelectorDropDownMenu() is in the Update function.

and

selectGamePieceFromTacticalTargetSelectorDropdown() is attached to the dropdown in the on value changed(32int) option.

I’m pretty new to Unity and C#, so maybe I’m missing something obvious.

Thanks again for your help, and if you have any answers regarding this, I’d love to hear them.

I believe you can get rid of all the code you’ve provided here and replace it by something similar to the following. Also, remove the callback you’ve provided in the Dropdown’s onValueChanged in the inspector.

public enum TacticalTargetType
{
    AlliedStarship,
    HostileStarship,
    AlliedStarbase,
    HostileStarbase,
    Asteroid
}

public class YourClass : MonoBehaviour
{
    public TacticalTargetType TacticalTargetType;

    public TMP_Dropdown TacticalTargetSelector;

    private void Start()
    {
        PopulateDropdown();
    }

    private void PopulateDropdown()
    {
        List<GameObject> selectedTacticalTargets = GetTacticalTargetObjects();
        TacticalTargetSelector.ClearOptions();
        TacticalTargetSelector.AddOptions(selectedTacticalTargets.ConvertAll(gameObject => gameObject.name));
        TacticalTargetSelector.onValueChanged.AddListener(index => OnTacticatTargetSelected(selectedTacticalTargets, index));
    }

    private List<GameObject> GetTacticalTargetObjects()
    {
        switch(TacticalTargetType)
        {
            case TacticalTargetType.AlliedStarship:  return listManagerGlobal.list_AlliedStarships;
            case TacticalTargetType.HostileStarship: return listManagerGlobal.list_HostileStarships;
            case TacticalTargetType.AlliedStarbase:  return listManagerGlobal.list_AlliedStarbase;
            case TacticalTargetType.HostileStarbase: return listManagerGlobal.list_HostileStarbase;
            case TacticalTargetType.Asteroid:        return listManagerGlobal.list_Asteroid;
        }
        return null;
    }

    public void OnTacticatTargetSelected(List<GameObject> selectedTacticalTargets, int index)
    {
        Debug.Log(selectedTacticalTargets[index] + " has been selected");
    }

    // Delete the function `addGamePiecesToTacticalTargetSelectorDropDownMenu`, and thus, don't call it from your Update method. Delete `selectGamePieceFromTacticalTargetSelectorDropdown` too.
}

Thank you so much for this, Hellium! I tried it as soon as I had some time to work on my game today.

I have one problem with this, however, and I don’t understand what is wrong. It’s with this block of code:

 private List<GameObject> GetTacticalTargetObjects()
 {
     switch(TacticalTargetType)
     {
         case TacticalTargetType.AlliedStarship:  return listManagerGlobal.list_AlliedStarships;
         case TacticalTargetType.HostileStarship: return listManagerGlobal.list_HostileStarships;
         case TacticalTargetType.AlliedStarbase:  return listManagerGlobal.list_AlliedStarbase;
         case TacticalTargetType.HostileStarbase: return listManagerGlobal.list_HostileStarbase;
         case TacticalTargetType.Asteroid:        return listManagerGlobal.list_Asteroid;
     }
 }

I get an error “List GetTacticalTargetObjects(). Not all code paths return a value.” So all the “index” code is red-underlined, too, then.

I’ve been looking into this error type and haven’t yet found an answer as to what the value is that should be returned.

Thanks again!

“return null” didn’t work, but “default : return null” did. Even so, the code marked “index” is still red-underlined.

It occurs, here:

TacticalTargetSelector.onValueChanged.AddListener(index => OnTacticatTargetSelected(selectedTacticalTargets, index));

and here:

 public void OnTacticatTargetSelected(List<GameObject> selectedTacticalTargets, index)
 {
     Debug.Log(selectedTacticalTargets[index] + " has been selected");
 }

Sorry for bothering you with this. Like I said, I’m pretty new to C#. But this is the first time I’ve had to ask for help directly. Every other problem I’ve encountered I’ve been able to figure out by either looking at other posts in the Answers section here or by watching tutorials on YouTube.

My game is coming along very nicely, I think, and this is a critical part.

Your help has been awesome!

So I added buttons allowing me to switch between the enum values — Allied Ships, Hostile Ships, etc. — and to repopulate dropdown accordingly, like this:

public void buttonSelectsAlliedShips()
{

    thisTacticalTargetType = TacticalTargetType.AlliedStarships;
    dropdown_TMP_TacticalTargetSelector.ClearOptions();
    PopulateDropdown();

}

public void buttonSelectsHostileShips()
{

    thisTacticalTargetType = TacticalTargetType.HostileStarships;
    dropdown_TMP_TacticalTargetSelector.ClearOptions();
    PopulateDropdown();

}

etc., etc…

And then the same things occur as did when I used my original code, that with the list of strings for tactical target type, and if/if else statements to determine which lists of gameobjects should be used. I’m not surprised, really, because the logic behind the string and ifs and enums and switch case statements are essentially the same. So, I get, again, an Argument out of range exception. But this time, after reading up on it, and carefully examining the inspector and the console, I believe I understand what is happening!

The list GetTacticalTargetObjects must be receiving, at Start, a “count” equal to the first list, list_AlliedStarships, and then when I change the list to, say, list_HostileStarships, the count doesn’t change, and all those Hostile Ships in the list after the original list count are considered outside the value range of the collection.

Also, upon changing the enum value, the console gives the index of every item from each list I’ve used at the same index. For example, if allied ships are 101, 102, 103, and I have now switched to hostile ships (201, 202, 203), and choose 203, the console will tell me I have selected 103, and then 203 is the final selected object. It lists it twice. If I switch then to Asteroids (301, 302, 303), and then back to Hostile Ships, and chose 203, the console will tell me I have chosen 103, 303, and then 203.

For the first matter, I’m thinking a solution might be to redefine the “count” or length value of the GetTacticalTargetObjects list when an new list is switched to. So if the Allied Ships list has a count of 5, and the hostile ships has a count of 10, then the GetTacticalTargetObjects count should be variable, 5 or 10, say. But I’m not really sure how to go about this. As for the second matter, about the selected value being 103, 303, and then settling on 203, the actual desired value, I don’t really have an idea as to how I could resolve this.

Anyway, I have learned so much from this!

Any thoughts?

Hello @KJPedersen it’s been a while since you posted this, but I am going through the same situation and, like you in 2020, I am new to Unity and C#. Would you be able to help me out with this?