ArgumentOutOfRangeException error Unity3D C # при попытке получить случайный элемент из списка после итерации по массиву - PullRequest
2 голосов
/ 11 июля 2019

Проблема: Я получаю ошибку ArgumentOutOfRangeException при попытке получить случайный элемент из списка после перебора массива.

Цель: Я пытаюсь активировать случайный дочерний игровой объект внутри родительского игрового объекта путем поиска тегов. Внутри родительского объекта есть несколько дочерних игровых объектов. Если этот игровой объект помечен тегом, который я ищу, я хочу выбрать его и добавить в новые списки на основе его тега. Затем, после итерации этого массива, я хочу получить случайный элемент для каждого из этих новых списков и установить его активным

[SerializeField] private List<Transform> heads = new List<Transform>();
[SerializeField] private List<Transform> bodys = new List<Transform>();
[SerializeField] private List<Transform> arms = new List<Transform>();
[SerializeField] private Transform[] bodyParts;

private GameObject head;
private GameObject backpack;
private GameObject arm;

void Start()
{
    bodyParts = this.gameObject.GetComponentsInChildren<Transform>();
    for (int i = 0; i < bodyParts.Length; i++)
    {
        switch (bodyParts[i].tag)
        {
            case "Head":
                heads.Add(bodyParts[i]);
                break;

            case "Arm":
                arms.Add(bodyParts[i]);
                break;

            case "Backpack":
                backpacks.Add(bodyParts[i]);
                break;

            default:
                Debug.Log("Not relevant");
                break;
        }
    }
    SetActiveBodyPart(heads, head);

    SetActiveBodyPart(arms, arm);

    SetActiveBodyPart(backpacks, backpack);
}

void SetActiveBodyPart(List<Transform> whichBodyParts, GameObject whichBodyPart)
{
    if (whichBodyParts != null)
    {
        whichBodyPart = whichBodyParts[Random.Range(0, whichBodyParts.Count)].gameObject;
        if (!whichBodyPart.activeSelf)
        {
            whichBodyPart.SetActive(true);
        }
    }
    else Debug.Log("Nothing here...");
}

Я получаю сообщение об ошибке в этой строке:

whichBodyPart = whichBodyParts [Random.Range (0, whichBodyParts.Count)]. GameObject;

Когда я вручную деактивирую все свои дочерние игровые объекты внутри родителя и запускаю игру, эти списки в редакторе Unity возвращают 0, но я ожидаю, что на выходе будут положительные целые числа

Ответы [ 2 ]

0 голосов
/ 11 июля 2019

Если вы хотите включить деактивированные компоненты в результаты GetComponentsInChildren, вам нужно включить параметр includeInactive и установить его на true.Кроме того, размещение this.gameObject перед GetComponentsInChildren является избыточным:

bodyParts = GetComponentsInChildren<Transform>(true);

Чтобы справиться с ситуацией, когда вы все равно получаете пустые списки, вы должны также включить проверку, которая позволяет избежать индексации в пустых списках:

if (whichBodyParts != null && whichBodyParts.Count > 0)
{
    whichBodyPart = whichBodyParts[Random.Range(0, whichBodyParts.Count)].gameObject;
    if (!whichBodyPart.activeSelf)
    {
        whichBodyPart.SetActive(true);
    }
}
else Debug.Log("Nothing here...");
0 голосов
/ 11 июля 2019

Возможно, проблема в том, что вы не проверяете, есть ли какие-либо элементы в списке, прежде чем пытаться получить к ним доступ.Вы можете проверить наличие элементов, используя свойство Count или метод расширения Any, и если мы объединим это с нулевым условным оператором (который вернет null, если объект слева равен null),мы можем сделать:

void SetActiveBodyPart(List<Transform> whichBodyParts, GameObject whichBodyPart)
{
    if (whichBodyParts?.Any == true)
    {
        whichBodyPart = whichBodyParts[Random.Range(0, whichBodyParts.Count)].gameObject;

        if (!whichBodyPart.activeSelf)
        {
            whichBodyPart.SetActive(true);
        }
    }
    else 
    {
        Debug.Log("Nothing here...");
    }
}

Другой альтернативой является проверка каждого условия отдельно, если вы хотите иметь более точную информацию в своих журналах:

void SetActiveBodyPart(List<Transform> whichBodyParts, GameObject whichBodyPart)
{
    if (whichBodyParts == null)
    {
        Debug.Log("whichBodyParts is null");
    }
    else if (!whichBodyParts.Any())
    {
        Debug.Log("whichBodyParts does not contain any items");
    }
    else
    {
        whichBodyPart = whichBodyParts[Random.Range(0, whichBodyParts.Count)].gameObject;

        if (!whichBodyPart.activeSelf)
        {
            whichBodyPart.SetActive(true);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...