Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > Unity > Уроки

Ответ
 
Опции темы
Старый 05.04.2016, 13:11   #1
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
ButtonWrapper

Класс-обёртка для удобства использования UI.Button.

Мне для игры понадобилось программно сделать кнопки с номерами уровней.
Сделал GridLayout, в который добавлял кнопки, создавая их из префаба.

Возникла проблема с событием onClick.

Код:
void InitLevelTasks()
{
    
levelChooser = new LevelChooser(imageForLevelTask);
    
Transform root PanelLevelsList;
    foreach (
Transform child in root) {
        
Destroy(child.gameObject);
    }
    
int count 48;
    for (
int k 0count; ++k) {
        var clone = 
GameObject.Instantiate(buttonPrefab);
        clone.
transform.SetParent(root);
        clone.
transform.localScale Vector3.one;

        var 
button = clone.GetComponent<Button>();

        
text button.transform.Find("Text").GetComponent<Text>();
        
text.text ""+k;

        
UnityAction act = new UnityAction (() => SelectLevel_Start (k));
        
button.onClick.AddListener(act);
    }

Любая кнопка при нажатии стартует уровень 48 - т.е. это значение К при выходе из цикла.
Я с ходу не понял, как можно впихнуть корректный параметр, и сделал обёртку для кнопки.

/* ButtonEventArgs */

public class ButtonEventArgs<TValue> : EventArgs {

    public 
TValue Value get; private set; }

    public 
ButtonEventArgs(TValue value) {
        
Value value;
    }

}


/* ButtonWrapper */

public class ButtonWrapper<TParam> {

    public 
event EventHandler<ButtonEventArgs<TParam>> OnClick;
    public 
GameObject gameObject;

    
Text text;
    
Button button;
    
TParam value;


    public 
ButtonWrapper(string captionTParam valueGameObject buttonPrefabTransform parent) {

        
this.value value;

        
gameObject GameObject.Instantiate(buttonPrefab);
        
gameObject.transform.SetParent(parent);
        
gameObject.transform.localScale Vector3.one;

        
button gameObject.GetComponent<Button>();
        
UnityAction act = new UnityAction(Clicked);
        
button.onClick.AddListener(act);

        
text button.transform.Find("Text").GetComponent<Text>();
        
text.text caption;

    }

    public 
void SetColor(string hex) {
        if (!
hex.StartsWith("#"))
            
hex "#" hex;
        
Color c;
        
ColorUtility.TryParseHtmlString(hexout c);
        
button.GetComponent<Image>().color c;
    }

    private 
void Clicked () {
        if (
OnClick != null)
            
OnClick(this, new ButtonEventArgs<TParam>(value));
    }


Что имеем?
1. Событие onClick в виде привычного с# event'a, на которое можно подписаться через +=
2. При клике - событие может содержать любой тип данных, какой мы укажем при создании враппера - достаём данные из параметра ButtonEventArgs.

Итоговый код создания кнопок (добавлена раскраска - 4 разных цвета по 12 кнопок в каждом блоке)

void InitLevelTasks()
{
    
levelChooser = new LevelChooser(imageForLevelTask);
    
Transform root PanelLevelsList;
    foreach (
Transform child in root) {
        
Destroy(child.gameObject);
    }
    
int count 48;
    for (
int k 0count; ++k) {
        
ButtonWrapper<intwrap = new ButtonWrapper<int>((1).ToString(), kprefabButtonLevelNumroot);
        
wrap.OnClick += (sendere) => {
            
SelectLevel_Start(e.Value);
        };
        
int v 12;
        
string color;
        if (
== 0)
            
color "41C64E";
        else if (
== 1)
            
color "F9FF67";
        else if (
== 2)
            
color "3381FF";
        else
            
color "FF4B3E";
        
wrap.SetColor(color);
    }

(Offline)
 
Ответить с цитированием
Старый 05.04.2016, 22:18   #2
seaman
Знающий
 
Регистрация: 08.01.2013
Адрес: Самара
Сообщений: 284
Написано 104 полезных сообщений
(для 180 пользователей)
Ответ: ButtonWrapper

Изучай Closure чтобы таких непоняток не было. Решается просто:
void InitLevelTasks()
{
    
levelChooser = new LevelChooser(imageForLevelTask);
    
Transform root PanelLevelsList;
    foreach (
Transform child in root) {
        
Destroy(child.gameObject);
    }
    
int count 48;
    for (
int k 0count; ++k) {
        var clone = 
GameObject.Instantiate(buttonPrefab);
        clone.
transform.SetParent(root);
        clone.
transform.localScale Vector3.one;

        var 
button = clone.GetComponent<Button>();

        
text button.transform.Find("Text").GetComponent<Text>();
        
text.text ""+k;
        
int j k;
        
UnityAction act = new UnityAction (() => SelectLevel_Start (j));
        
button.onClick.AddListener(act);
    }

Т.е. делаешь временную переменную, которой присваиваешь текущее значение. И уже ее используешь в лямбда выражении
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо seaman за это полезное сообщение:
St_AnGer (05.04.2016), Жека (06.04.2016)
Старый 05.04.2016, 23:17   #3
St_AnGer
Элита
 
Аватар для St_AnGer
 
Регистрация: 21.01.2010
Адрес: Россия, Рязанская область, г.Михайлов
Сообщений: 2,067
Написано 1,185 полезных сообщений
(для 2,828 пользователей)
Ответ: ButtonWrapper

Сообщение от seaman Посмотреть сообщение
Изучай Closure чтобы таких непоняток не было. Решается просто:
void InitLevelTasks()
{
    
levelChooser = new LevelChooser(imageForLevelTask);
    
Transform root PanelLevelsList;
    foreach (
Transform child in root) {
        
Destroy(child.gameObject);
    }
    
int count 48;
    for (
int k 0count; ++k) {
        var clone = 
GameObject.Instantiate(buttonPrefab);
        clone.
transform.SetParent(root);
        clone.
transform.localScale Vector3.one;

        var 
button = clone.GetComponent<Button>();

        
text button.transform.Find("Text").GetComponent<Text>();
        
text.text ""+k;
        
int j k;
        
UnityAction act = new UnityAction (() => SelectLevel_Start (j));
        
button.onClick.AddListener(act);
    }

Т.е. делаешь временную переменную, которой присваиваешь текущее значение. И уже ее используешь в лямбда выражении
О! Только вчера до этого открытия своим мозгом допёр и тоже именно для гуя докапывался, что бы на генерируемые кнопки вешать события вот такого плана.
__________________
Main PC:
Intel Core i5 4260U 1.44 GHz + LPDDR3 1x4096 1600 MHz + Intel HD Graphics 5000.

Asus Ёжик T101-MT:
Intel Atom N-570 1.66 Ghz + DDR2 2x1024 800 Mhz + Intel GMA 3150 128 Mb DDR2


Скачать Doom 2D: Remake v0.3.8a
(Offline)
 
Ответить с цитированием
Старый 06.04.2016, 05:08   #4
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,376
Написано 491 полезных сообщений
(для 886 пользователей)
Ответ: ButtonWrapper

Блин, а я внутри лямбды делал переменную, и конечно она не сработала, т.к. код вызывается при нажатии, и я получал тот же count.
Спасибо!
(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 15:12.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com