Пятница, 29 Марта 2024, 10:00

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Проблема с программным созданием событий UI (C#)
Проблема с программным созданием событий UI
CmaujlukДата: Суббота, 09 Января 2016, 18:00 | Сообщение # 1
участник
Сейчас нет на сайте
Всем привет.
Скажу сразу случай тяжелый, требуется эксперт).
Программируя эвент нажатия UI кнопки столкнулся с одной проблемой.
Код

    int i = 0;
    ShopInsets[i].onClick.AddListener(delegate {WindowShopInsetChange(i); });
    i = 1;

Что тут происходит:
ShopInsets[i] - Выбираем кнопку из массива, кнопка захеширована (.GetComponent<Button>())
Далее на эвент onClick т.е. клик мышкой назначаем метод delegate {WindowShopInsetChange(i); }
delegate используется для того, чтобы метод можно было использовать с параметром (i), иначе работать отказывается.
В чём собственно вопрос и почему такой кусок кода.
Если мы кликнем мышкой по кнопке то в метод уйдет цифра 1, а не 0.
Если же мы используем за место i просто число
Код
ShopInsets[i].onClick.AddListener(delegate {WindowShopInsetChange( i ); });

Заменим i на 0 и получим
Код
ShopInsets[i].onClick.AddListener(delegate {WindowShopInsetChange( 0 ); });

То в метод нормально передастся ноль при клике на кнопку.
Как я понял, компилятор передает не текущее значение поля i, а берет ссылку на i
Вопрос. Есть возможность заставить компилятор взять число из поля i?
Если кнопок много то прогнать все циклом куда проще чем прописывать все вручную.
Заранее спасибо, с меня +.


Не жадный на плюсы.
Наши проекты:
Clicker Mine Mania 2 - Увлекательный кликер в стиле Minecraft
Angry Bee Evolution - Эволюция с элементами кликера
Чего не хватает? - Викторина на логику"
YellowAfterlifeДата: Суббота, 09 Января 2016, 18:18 | Сообщение # 2
Сейчас нет на сайте
Это особенность работы делегатов - делегат не просто берет переменную "по ссылке", а имеет доступ ко всем локальным переменным метода, что его создал. Решается добавлением функции, которая "строит" делегаты,
Код
UnityEngine.Events.UnityAction GetWindowShopInsetChange(int i) {
return delegate { WindowShopInsetChange(i); };
}
// ...
ShopInsets[i].onClick.AddListener(GetWindowShopInsetChange(i));

Поскольку в таком случае делегат будет получать отдельно взятое значение, переданное в функцию, код будет работать правильно.
Общий тест:




Сообщение отредактировал YellowAfterlife - Суббота, 09 Января 2016, 19:37
CmaujlukДата: Суббота, 09 Января 2016, 19:09 | Сообщение # 3
участник
Сейчас нет на сайте
Цитата YellowAfterlife ()
Action GetWindowShopInsetChange(int i) {

Хорошая попытка, но к со жалению не работает.
Насколько я знаю
Цитата YellowAfterlife ()
.onClick.AddListener

Эвент принадлежащий юнити, от сюда ошибка компилятора
Ошибка CS1503 Аргумент 1: не удается преобразовать из "System.Action" в "UnityEngine.Events.UnityAction".

Добавлено (09 января 2016, 19:09)
---------------------------------------------
Попробовал и так
Код
ShopInsets[i].onClick.AddListener(delegate { GetWindowShopInsetChange(i); });

Тоже не выходит.


Не жадный на плюсы.
Наши проекты:
Clicker Mine Mania 2 - Увлекательный кликер в стиле Minecraft
Angry Bee Evolution - Эволюция с элементами кликера
Чего не хватает? - Викторина на логику"


Сообщение отредактировал Cmaujluk - Суббота, 09 Января 2016, 19:11
YellowAfterlifeДата: Суббота, 09 Января 2016, 19:38 | Сообщение # 4
Сейчас нет на сайте
Цитата Cmaujluk ()
Эвент принадлежащий юнити, от сюда ошибка компилятора
Ошибка CS1503 Аргумент 1: не удается преобразовать из "System.Action" в "UnityEngine.Events.UnityAction".

Добавлено (09 января 2016, 19:09)
---------------------------------------------
Попробовал и так

В первую очередь нужно было попробовать заменить возвращаемый тип функции на тот, который оно просит. Это работает. Обновил код в моем ответе.


CmaujlukДата: Суббота, 09 Января 2016, 20:06 | Сообщение # 5
участник
Сейчас нет на сайте
Цитата YellowAfterlife ()
В первую очередь нужно было попробовать заменить возвращаемый тип функции на тот, который оно просит. Это работает. Обновил код в моем ответе.

И правда, я попробовал Events.UnityAction Т.к. UnityEngine подключен, но оно не сработало, а UnityEngine.Events.UnityAction зашло.
Спасибо за ответ, Вы мне очень помогли.


Не жадный на плюсы.
Наши проекты:
Clicker Mine Mania 2 - Увлекательный кликер в стиле Minecraft
Angry Bee Evolution - Эволюция с элементами кликера
Чего не хватает? - Викторина на логику"
OpenGOOДата: Суббота, 09 Января 2016, 20:14 | Сообщение # 6
почти ветеран
Сейчас нет на сайте
А так что не работает?
Код
delegate(int i){ WindowShopInsetChange( i ); }


Мои проекты:
- Свободный и открытый клон World Of Goo
- TrueEngine2D (2D игровой фреймворк основанный на FreeBASIC)

[GameMaker: Studio v1.4.9999]
CmaujlukДата: Суббота, 09 Января 2016, 20:47 | Сообщение # 7
участник
Сейчас нет на сайте
Цитата OpenGOO ()
delegate(int i){ WindowShopInsetChange( i ); }

Так не работает


Не жадный на плюсы.
Наши проекты:
Clicker Mine Mania 2 - Увлекательный кликер в стиле Minecraft
Angry Bee Evolution - Эволюция с элементами кликера
Чего не хватает? - Викторина на логику"
OpenGOOДата: Суббота, 09 Января 2016, 21:01 | Сообщение # 8
почти ветеран
Сейчас нет на сайте
Всё понял. Надо сперва класс создать с одним методом, (в объекте будет хранится значение i), и передать этот метод как делегат.

Еще более простой вариант, если нужно с циклом.

Код
for (int i = 0; i < MAX_SIZE; ++i) {
  int ii = i;
  ShopInsets[i].onClick.AddListener(delegate {WindowShopInsetChange(ii); });
}


Мои проекты:
- Свободный и открытый клон World Of Goo
- TrueEngine2D (2D игровой фреймворк основанный на FreeBASIC)

[GameMaker: Studio v1.4.9999]


Сообщение отредактировал OpenGOO - Воскресенье, 10 Января 2016, 11:13
seamanДата: Понедельник, 11 Января 2016, 07:55 | Сообщение # 9
старожил
Сейчас нет на сайте
По первому посту. Чтобы понять почему так происходит читаем про "замыкания".
Например тут: http://habrahabr.ru/post/36601/
Например так должно работать
Код
    int i = 0;
    int j = i;
    ShopInsets[i].onClick.AddListener(delegate {WindowShopInsetChange(j); });
    i = 1;

Если j нигде в данном методе не меняется.
Что, кстати в предыдущем посте и написали.


Сообщение отредактировал seaman - Понедельник, 11 Января 2016, 07:58
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Проблема с программным созданием событий UI (C#)
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг