2016-05-26 7 views
2

В одной из моих петель, которую я использую для изменения настроек моих кнопок, я также использую функцию AddListener, а не ту, что находится в инспекторе. У меня есть 5 элементов, дающих диапазон «i» от 0-4, но когда я печатаю «i» через функцию, которую он должен вызывать, он всегда регистрирует 5, независимо от того, какую кнопку я нажимаю, что странно, так как «i» никогда даже не достигает 5. Любая идея?Необъяснимое увеличение переменной

P.s. Я использую CustomEditor, чтобы показать 2 кнопки «Предварительный макет» и «Удалить предварительный просмотр» в инспекторе.

Код:

using UnityEngine; 
using System.Collections; 
using UnityEditor; 
using UnityEngine.UI; 

public class RateMeManager : MonoBehaviour { 

    public GameObject rateMeCanvas; 
    public Sprite emptyStar, fullStar, button; 
    public float spriteWidth, spriteHeight, spritePadding; 

    [HideInInspector] 
    public GameObject currentCanvas, tempButton; 

    void Start() { 
     RemovePreview(); 
     GenerateStars(); 
    } 

    // Update is called once per frame 
    public void GenerateStars() { 
     RectTransform myRectTransform; 
     if (currentCanvas != null) 
     { 
      GameObject temp; 
      temp = currentCanvas; 
      DestroyImmediate(temp); 
     } 
     currentCanvas = Instantiate(rateMeCanvas, Vector3.zero, Quaternion.identity) as GameObject; 
     GameObject subCanvas = currentCanvas.transform.FindChild("subCanvas").gameObject; 
     myRectTransform = subCanvas.GetComponent<RectTransform>(); 
     myRectTransform.sizeDelta = new Vector2((5*spriteWidth) + (4*spritePadding), spriteHeight); 
     myRectTransform.anchoredPosition = Vector2.zero; 
     Button[] buttons = subCanvas.GetComponentsInChildren<Button>(); 
     float[] positions = new float[] {((2*spriteWidth)+(2*spritePadding))*-1, ((1 * spriteWidth) + (1 * spritePadding)) * -1 , 0, ((1 * spriteWidth) + (1 * spritePadding)), ((2 * spriteWidth) + (2 * spritePadding))}; 
     for (int i = 0; i < buttons.Length; i++) 
     { 
      Debug.Log(i); 
      tempButton = buttons[i].gameObject; 
      tempButton.GetComponent<Button>().image.sprite = emptyStar; 
      myRectTransform = buttons[i].GetComponent<RectTransform>(); 
      myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight); 
      myRectTransform.anchoredPosition = new Vector2(positions[i], 0); 
      tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(i)); 
     } 
    } 

    public void RemovePreview() 
    { 
     DestroyImmediate(currentCanvas); 
    } 

    private void OnGivenRate(int stars) 
    { 
     Debug.Log("pressed star: " + stars); 
    } 

    public class RateMeEditor 
    { 
     [CustomEditor(typeof(RateMeManager))] 
     public class button : Editor 
     { 
      public override void OnInspectorGUI() 
      { 
       base.OnInspectorGUI(); 

       RateMeManager myScript = (RateMeManager)target; 
       if (GUILayout.Button("Preview Layout")) 
       { 
        myScript.GenerateStars(); 
       } 
       if (GUILayout.Button("Delete Preview")) 
       { 
        myScript.RemovePreview(); 
       } 
      } 
     } 
    } 
} 
+0

Пожалуйста, отлаживайте и проверяйте, является ли ваша 'button.Length' равной 5 или нет. – SeM

+4

любите слово «увеличение» – Fattie

+0

@JoeBlow даже не заметил, что пока вы это не сказали. не знаю почему, но я думаю, что это смешно – Programmer

ответ

5

Ваша ошибка здесь:

tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(i)); 

Вы должны хранить i в переменной перед передачей его OnGivenRate или использовать замыкание. Потому что в конце цикла i равен 5. Вот почему при нажатии на кнопке i дисплеев 5.

Так что:

var rate = i; 
tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(rate)); 

или

Action<int> OnGivenRateClosure(int rate) 
{ 
    return() => OnGivenRate(rate); 
} 

с

tempButton.GetComponent<Button>().onClick.AddListener(OnGivenRateClosure(i)); 
+0

Спасибо! Как я прокомментировал другие предложения, он работает таким образом в Android Studio с использованием Java, поэтому я не получил его для работы здесь (может быть, это что-то, что они специально поместили в Android Studio) В любом случае, только добавив это в цикл, все работает сейчас! 'int rate = i; tempButton.GetComponent

+0

Я рад, что помог вам :) –

+0

Немного темы здесь, но как я могу добавить пустые строки в Комментарий вроде этого? Я не могу получить код, который будет хорошо отформатирован haha ​​... – sdieters

1

Вы получаете доступ замыкания, так называемая функция внутри цикла for получает значение i только через некоторое время, когда цикл находится в другом цикле и i уже изменен ,

Другое дело. При записи:

for(int i = 0; i < 5; i++) 

код выполняет операторы внутри цикла for с i значениями 0, 1, 2, 3, 4, но последнее значение i является . Фактически, когда цикл с завершен, i увеличивается, выполняется проверка «i < 5», он выводит false, поэтому цикл завершается.

+0

Проверьте также [это сообщение] (http://stackoverflow.com/questions/304258/access-to-modified-closure-2), это похоже. –

+0

Спасибо, это имеет смысл, однако в Android Studio это работает так, поэтому здесь замешана путаница. Отличное объяснение tho! – sdieters

1

Вы ссылка на i на вашем for -loop:.

tempButton.GetComponent() onClick.AddListener (() => OnGivenRate (я));

И вы используете анонимный метод для вызова OnGivenRate(i). Этот фрагмент кода будет находиться вне области вашего for -loop, но он будет иметь доступ к переменной i. Переменная, когда она ссылается на анонимный метод () => OnGivenRate(i), скорее всего будет иметь i=5 (когда выйдет for -loop).

+0

, что имеет смысл, спасибо! По какой-то причине в Android Studio (с использованием Java) он работает так, как я сделал это в OP. Новые вещи узнавались каждый день =) – sdieters

+0

Java может иметь дело с закрытием, отличным от C#. Будет интересный вопрос. ;) –

0

Ваш код является избыточным. У вас уже есть кнопки в виде массива перед циклом for, после чего вы преобразовали его gameObject (tempButton), затем снова в кнопку ... Это похоже на справочную проблему. Просто замените цикл for кодом ниже.

Для отображения от 0 до 4:

for (int i = 0; i < buttons.Length; i++) 
{ 
    buttons[i].image.sprite = emptyStar; 
    myRectTransform = buttons[i].GetComponent<RectTransform>(); 
    myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight); 
    myRectTransform.anchoredPosition = new Vector2(positions[i], 0); 
    buttons[i].onClick.AddListener(() => OnGivenRate(i)); 
} 

Для отображения 1 до 5:

for (int i = 0; i < buttons.Length; i++) 
{ 
    buttons[i].image.sprite = emptyStar; 
    myRectTransform = buttons[i].GetComponent<RectTransform>(); 
    myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight); 
    myRectTransform.anchoredPosition = new Vector2(positions[i], 0); 
    buttons[i].onClick.AddListener(() => OnGivenRate(i+1)); 
} 

Обратите внимание на разницу: Кнопки [I] .onClick.AddListener (() => OnGivenRate (i + 1));

Смежные вопросы