Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity Button OnClick AddListener Issue - Same callback as last item in For Each Loop

Tags:

c#

loops

onclick

So I have a script (Unity C#) that runs an IEnumerator function that generates an array of answers and I want to present them in a list format.

So I use:

public Button QuestionButton;

void Start(){
    StartCoroutine(PresentQuestion());
}

IEnumerator PresentQuestion(){
    CurrentStage = Stage.QuestionStart;

    CurrentQuestion = "How many times do we have to do this to make it work?";
    Answers.Add ("1");
    Answers.Add ("2");
    Answers.Add ("3");
    Answers.Add ("4");

    float newY = 80.0f;
    foreach(string answer in Answers){
        newY-=65.0f;
        string locanswer = answer;
        Button btn = Instantiate(QuestionButton);
        btn.transform.position = new Vector3(225, newY, 0);
        btn.transform.SetParent(QuestionUI.transform, false);
        btn.gameObject.SetActive(true);
        btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
        btn.onClick.AddListener(() => AnswerClicked(locanswer));
    }
    QuestionText.text = CurrentQuestion;
}

void AnswerClicked(string value){
    print (value);
}

The QuestionButton is a button gameobject I linked in the inspector and it instantiates fine, the text is set fine, but it is when I add the listener.

When I go to click on the button I get the last string or _answer in the loop "every time".

I am not sure why each new Button (btn) object that is instantiated would not get its own Listener at AnswerClicked. Can anyone please explain?

FYI: QuestionUI is my canvas.

Thanks.

UPDATE :

This code works, but my previous problem still exists. I will attempt to update with my actual code.

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

public class Testing : MonoBehaviour {

public string CurrentQuestion;
public ArrayList Answers = new ArrayList();

public Button QuestionButton;
public GameObject QuestionUI;
public Text QuestionText;

void Start(){
    StartCoroutine(PresentQuestion());
}

IEnumerator PresentQuestion(){
    CurrentQuestion = "How many times do we have to do this to make it work?";
    Answers.Add ("1");
    Answers.Add ("2");
    Answers.Add ("3");
    Answers.Add ("4");

    float newY = 80.0f;
    foreach(string answer in Answers){
        newY-=65.0f;
        string locanswer = answer;
        Button btn = Instantiate(QuestionButton);
        btn.transform.position = new Vector3(225, newY, 0);
        btn.transform.SetParent(QuestionUI.transform, false);
        btn.gameObject.SetActive(true);
        btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
        btn.onClick.AddListener(() => AnswerClicked(locanswer));
    }
    QuestionText.text = CurrentQuestion;

    return null;
}

void AnswerClicked(string value){
    print (value);
}
}
like image 871
DrRocker Avatar asked Nov 16 '25 08:11

DrRocker


1 Answers

I had the same issue and I found that setting the onClick listener in a separate method worked for me.

Here's how I would do it in this case:

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

public class Testing : MonoBehaviour {

    public string CurrentQuestion;
    public ArrayList Answers = new ArrayList();

    public Button QuestionButton;
    public GameObject QuestionUI;
    public Text QuestionText;

    void Start(){
        StartCoroutine(PresentQuestion());
    }

    IEnumerator PresentQuestion(){
        CurrentQuestion = "How many times do we have to do this to make it work?";
        Answers.Add ("1");
        Answers.Add ("2");
        Answers.Add ("3");
        Answers.Add ("4");

        float newY = 80.0f;
        foreach(string answer in Answers){
            newY-=65.0f;
            Button btn = Instantiate(QuestionButton);
            btn.transform.position = new Vector3(225, newY, 0);
            btn.transform.SetParent(QuestionUI.transform, false);
            btn.gameObject.SetActive(true);
            btn.transform.FindChild("Text").GetComponent<Text>().text = locanswer;
            SetButtonOnClick(btn, answer);
        }
        QuestionText.text = CurrentQuestion;

        return null;
    }

    void SetButtonOnClickAnswer(Button button, string value){
        button.onClick.AddListener(() => AnswerClicked(value));
    }

    void AnswerClicked(string value){
        print (value);
    }
}

(Disclaimer: I haven't tested this but I am running a very similar code in my project and this solved the issue.)

like image 85
Amos Wazana Avatar answered Nov 18 '25 01:11

Amos Wazana



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!