Home > Blockchain >  How to remove the previous button listener before adding a new listener in unity?
How to remove the previous button listener before adding a new listener in unity?

Time:07-29

I have a QuestionGenerator.cs script which at the start, creates a question that is a comparison between two randomly generated numbers that can be up to 3 digits. When the user clicks on the correct option button, another random question is generated.

Let's say the numbers are a and b. I pass a - b and the array { "<", "=", ">" } as the arguments to the method SetButtonListeners(). The logic goes like this:

  • When a - b is less than 0, the sign should be <
  • When a - b is equal to 0, the sign should be =
  • When a - b is greater than 0, the sign should be >

Actual question:

Every time SetButtonListeners() is called, listeners are added to the button, hence when it's called the second time, a listener already exists to that button. I want to remove the previously added listener if there's any and then add the new listener. As a hack, I am currently removing all the listeners the button has

buttons[i].onClick.RemoveAllListeners();

How do I go with only removing the previously set button listener and not all the listeners the button has?


A minimal reproducible code to depict my problem:

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

public class QuestionsGenerator : MonoBehaviour {
    static public QuestionsGenerator instance { get => return s_Instance; }
    static private QuestionsGenerator s_Instance;

    public Text questionText;
    public Button[] buttons; // length is 3

    private void Awake() {
        if (s_Instance == null) {
            s_Instance = this;
        } else {
            Destroy(gameObject);
        }
    }

    private void Start() {
        GenerateQuestion();
    }

    private void GenerateQuestion() {
        ComparisionUpto3Digits();
    }

    private void ComparisionUpto3Digits() {
        int a = Random.Range(1, 1000);
        int b = Random.Range(1, 1000);

        questionText.text = a   " ___ "   b;

        int ans = a - b;
        string[] options = { "<", "=", ">" };
        SetButtonListeners(ans, options);
    }

    private void SetButtonListeners(int answer, string[] options) {
        // length of both buttons[] and options[] is the same
        for (int i = 0; i < buttons.Length; i  ) {
            buttons[i].GetComponentInChildren<Text>().text = options[i];

            // removing all listeners here
            buttons[i].onClick.RemoveAllListeners();

            if ((answer < 0 && i == 0) || (answer == 0 && i == 1) || (answer > 0 && i == 2)) {
                buttons[i].onClick.AddListener(() => {
                    HandleCorrectAnswer();
                });
            } else {
                buttons[i].onClick.AddListener(() => {
                    HandleWrongAnswer();
                });
            }
        }
    }

    private void HandleCorrectAnswer() {
        GenerateQuestion();
    }

    private void HandleWrongAnswer() {
        Debug.Log("Game Over");
    }
}

CodePudding user response:

Constantly adding new listeners does not seem like a good solution. Handle correct/wrong answer in the same listener instead by passing a different argument to the listening function. You can pass parameters like this: https://answers.unity.com/questions/1288510/buttononclickaddlistener-how-to-pass-parameter-or.html

EDIT: To be more precise, you can simply do something like this:

private int a,b;

private void Awake(){
    for(int buttonIndex = 0; buttonIndex < buttons.Length; buttonIndex  ){
        int closureIndex = buttonIndex;          
        buttons[closureIndex].onClick.AddListener(delegate{HandleAnswer(closureIndex);});
    }
}

private void HandleAnswer(int buttonIndex){
    int answer = a-b;
    if ((answer < 0 && buttonIndex == 0) || (answer == 0 && buttonIndex == 1) || (answer > 0 && buttonIndex == 2)) {
        [good answer]
    }else{
        [wrong answer]
    }
}

EDIT: Added closure index according to comment (https://answers.unity.com/questions/1376530/add-listeners-to-array-of-buttons.html?childToView=1376656#answer-1376656)

  • Related