Add listener to multiple buttons
I have a menuController that creates a matrix of buttons which represent the levels. When a certain button is clicked, that level should be loaded. However, it doesn't matter which button I click, I always get level 25 returned... altough the highest possible level is only 20. I think this has something to do with the lambda expression that is set to every button over and over but I don't know how to fix this.
public class MenuController : MonoBehaviour {
public GameObject btnLevelPrefab;
public GameObject levelContainer;
public GameObject communicationManager;
private GameObject[,] btnLevels;
void Start () {
btnLevels = new GameObject[4, 5];
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 4; j++)
{
btnLevels[j,i] = Instantiate(btnLevelPrefab, new Vector3(63 + j*90, 500 - i*90, 0), Quaternion.identity) as GameObject;
btnLevels[j,i].transform.SetParent(levelContainer.transform);
btnLevels[j,i].GetComponentInChildren<Text>().text = (j+1+i*4).ToString();
btnLevels[j,i].GetComponent<Button>().onClick.AddListener(() => { startLevel(j + 1 + i * 4); });
}
}
}
private void startLevel(int level)
{
Debug.Log(level); // Returns 25 everytime???
communicationManager.GetComponent<CommunicationManager>().setLevel(level);
Application.LoadLevel(1);
}
}
Answer by Prezzo · May 25, 2016 at 04:19 PM
SOLUTION!!
For some reason the AddListener can only be attached to every single button when I send the button as parameter instead of an integer that represents the level.
The new working code is now:
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 4; j++)
{
btnLevels[j,i] = Instantiate(btnLevelPrefab, new Vector3(63 + j*90, 500 - i*90, 0), Quaternion.identity) as GameObject;
btnLevels[j,i].transform.SetParent(levelContainer.transform);
btnLevels[j,i].GetComponentInChildren<Text>().text = (j+1+i*4).ToString();
Button btnTemp = btnLevels[j, i].GetComponent<Button>();
btnLevels[j, i].GetComponent<Button>().onClick.AddListener(() => { startLevel(btnTemp); });
}
}
}
private void startLevel(Button btnLevel)
{
Debug.Log(btnLevel.GetComponentInChildren<Text>().text);
communicationManager.GetComponent<CommunicationManager>().setLevel(int.Parse(btnLevel.GetComponentInChildren<Text>().text));
Application.LoadLevel(1);
}
Answer by Thajocoth · May 25, 2016 at 05:14 PM
The issue was that adding the functionality that way doesn't preserve the state of the variables used inside it.
int i = 5;
AddListener(() => { function(i); });
i++;
This will call function(6) when clicked, because i later became 6. The fact that i was 5 when the listener was set up is irrelevant.
I've been burned by this before as well. I wish there was a way to say "The current value of" instead of "Whatever the value will be of" when doing that.
(j + 1 + i * 4)
may as well be
(4 + 1 + 5 * 4)
Which is 25.
Your answer
Follow this Question
Related Questions
Add listenner to button in loop error 0 Answers
How to use Button.OnClick.AddListener? 2 Answers