Нажатие кнопки Unity не срабатывает

Я посмотрел на пост, расположенный здесь, который посвящен той же проблеме, но он не иллюстрирует, что не так, и не решает мою проблему.

Я создал сборный Canvas с несколькими кнопками на панели. Я создаю экземпляр сборника во время выполнения и беру все Button объекты внутри панели. Затем я добавляю слушателя к onClick() событие для всех кнопок, вызывающих один и тот же clicked() метод

public class GameOptions
{
    private GameObject canvas;

    public GameOptions(GameObject canvas)
    {
        this.canvas = canvas;
        GameObject.Instantiate(canvas);        
        Text[] textObjects = canvas.GetComponentsInChildren<Text>();
        Button[] buttonObjects = canvas.GetComponentsInChildren<Button>();

        for (int i = 0; i < buttonObjects.Length; i++)
        {
            Debug.Log(buttonObjects[i].name);
            buttonObjects[i].onClick.AddListener(() => clicked());
            buttonObjects[i].onClick.Invoke();
        }
    }

    public void clicked()
    {
        Debug.Log("Clicked!");
    }
}

Обратите внимание, что когда я вызываю событие через код, clicked() называется и "нажал!" правильно выводится на консоль.

Однако ни одна из кнопок не запускает событие при нажатии. Я также заметил, что массив PersistentCalls.Calls в OnClick в Inspector содержит 0 элементов для всех кнопок во время выполнения.

Я использую Unity 2017.4.3f1 в Windows 10 64.

2 ответа

Решение

Тот факт, что вы не бросаете никаких исключений, а onClick.Invoke() Это наводит на мысль, что проблема в том, что какой-то другой элемент потребляет щелчки. Не имея вашего проекта передо мной, я могу только внести некоторые предложения.

  • Убедитесь, что между камерой и кнопками нет элементов пользовательского интерфейса (таких как прозрачные панели или изображения); Вы можете перемещаться по объектам во время выполнения, чтобы увидеть, не слишком ли они близки и потребляют щелчок.
  • Убедитесь, что родительский холст не имеет CanvasGroup с Interactable установить в ложь.
  • Ищите любые пустые объекты / коллайдеры / слушатели, которые могут блокировать радиопередачи.

Удачи!


редактировать

После перечитывания вашего кода и повторного связанного поста я обнаружил ошибку в вашем коде.

В вашем GameOptions конструктор класса, вы на самом деле не ссылаетесь на экземпляр объекта при сборе объектов. Это ты написал:

this.canvas = canvas;
GameObject.Instantiate(canvas);
Text[] textObjects = canvas.GetComponentsInChildren<Text>();

Если вы посмотрите, что именно происходит, вы назначаете поле canvas в префаб, который был передан в параметр конструктора. После того, как вы сделаете присваивание, вы создаете экземпляр префаба с параметром, без какой-либо ссылки на экземпляр объекта.

После этого вы звоните GetComponentsInChildren на префаб не сам экземплярный объект. Вот почему onClick.Invoke() увольняют, потому что объекты существуют на сборном; они просто не те объекты, которые вы ищете.

Я реорганизовал ваш конструктор, который должен решить вашу проблему.

public GameOptions(GameObject canvas)
{
    //here we instantiate the canvas item, assigning it to the field
    this.canvas = GameObject.Instantiate(canvas);  

    //then we reference the field item, instead of the parameter item
    Text[] textObjects = this.canvas.GetComponentsInChildren<Text>();
    Button[] buttonObjects = this.canvas.GetComponentsInChildren<Button>();
    for(int i = 0; i < buttonObjects.Length; i++)
    {
        Debug.Log(buttonObjects[i].name);
        buttonObjects[i].onClick.AddListener(() => clicked());
        buttonObjects[i].onClick.Invoke();
    }
}

Несколько заметок

  • Вы должны использовать Canvas предмет вместо GameObject, даже если вы никогда не используете членов Canvas учебный класс; это облегчает чтение в будущем и предотвращает случайное создание new GameOptions(someRandomButton) который просто ничего не сделает, когда вы попытаетесь получить доступ к детям. Canvas объект наследуется от GameObject так что у вас будет все, что вам нужно.
  • Вы должны рассмотреть возможность использования другой схемы именования; это очень субъективное мнение, и по этому вопросу много споров, если вы ищете SO. Лично я выбираю префикс подчеркивания в частных полях, таких как private GameObject _canvas;это заставляет меня не сомневаться, что я не забыл this потому что по сути параметры и поля будут иметь различные и уникальные схемы именования.

Прими мой совет с крошкой соли! Существует много способов решения проблемы, поэтому в конечном итоге выберите наиболее удобный для вас вариант.

Просто чтобы помочь другим людям, столкнувшимся с этой досадной проблемой.

Помимо общих конфигурацийEventSystemиCanvas, есть еще одна причина неотзывчивости кнопок пользовательского интерфейса, которую я обнаружил в своих собственных программах, и я думаю, что она может быть причиной для большинства людей.

Проблема возникает, когда вы добавляете объект самостоятельно (очень часто), не помечая его. Если вы понятия не имеете, как его пометить, то, скорее всего, это ваша причина.

ключевой момент :cameraты используешь сstandalone input moduleдолжен быть помечен какMainCamera. В противном случае он не распознает объекты без коллайдера.

Другие вопросы по тегам