Why does the scripts call both parts at the same time?

Hello everyone, new to Unity and C#. I’m writing a script for my maths game. The scripts in question are used within the game to check the player’s answers to a few questions. The first script, a multichoice script, displays three choices for a question and takes in the student’s answer. It is attached to an answer script that I’ll include after this. This script works fine as far as I’m aware.

using TMPro;
using UnityEngine;

public class S4MCQScript : MonoBehaviour
{
    public string MCQuestion;
    public string[] MCAnswers;
    public int correctAns;
    public GameObject[] choices;
    public TextMeshProUGUI QTxt;
    public S4InputScript inputScript;

    public void generateMCQ()
    {
        QTxt.text = MCQuestion; //set question text to stored question
        setAnswers();
    }

    void setAnswers() //set answers to each choice buttons
    {
        for (int i = 0; i < choices.Length; i++)
        {
            choices[i].GetComponent<AnswerScript>().isCorrect = false;
            choices[i].transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = MCAnswers[i]; //change the text in the buttons to the possible choices text

            if (correctAns == i + 1)
            {
                choices[i].GetComponent<AnswerScript>().isCorrect = true; //set the value of the button's isCorrect to true
                                                                          //if the value assigned to it is the correct one
            }
        }
    }

    private void Start()
    {
        generateMCQ();
    }
}

The second script checks if the player’s answer is correct and if it is, it disables the choice buttons that are associated with the multichoice question and enables the input box that will be used in the second and third parts of the stage. It progresses to the second part regardless of whether their answer is right or not.

using UnityEngine;

public class AnswerScript : MonoBehaviour
{
    public bool isCorrect = false;
    public S4MCQScript qManager;
    public S4InputScript inputScript;
    public GameObject UI1;
    public GameObject UI2;
    public int wrongCounter;

    public void Answer()
    {
        if (isCorrect)
        {
            Debug.Log("Correct answer");
            inputScript.part2(wrongCounter); //call the part2() method from the referenced input script, passing in wrongCounter as a parameter
            UI1.SetActive(!UI1.activeSelf); //disable the first part's UI items (the buttons)
            UI2.SetActive(!UI2.activeSelf); //enable the second & third parts' UI items (the input box)
        }
        else
        {
            wrongCounter++; //increment the wrongCounter when the question is answered incorrectly
            inputScript.part2(wrongCounter); //call the part2() method anyways
            UI1.SetActive(!UI1.activeSelf);
            UI2.SetActive(!UI2.activeSelf);

        }
    }
}

The script is attached to each of the multichoice question buttons.
The third script, which is the biggest, is the script used to evaluate the player’s input within the input box by comparing them to each part’s stored answer. It begins with the second part of the stage and if the answers are the same (or not), it should progress them to the third part.

using TMPro;
using UnityEngine;

public class S4InputScript : MonoBehaviour
{
    public string P2Question;
    public string P3Question;
    public string P2Answer;
    public string P3Answer;
    public TextMeshProUGUI QTxt;
    public TMP_InputField inputBox;
    public GameObject winOverlay; //overlay thats displayed when the student wins - finishes with less than 3 mistakes
    public GameObject failOverlay; //overlay thats displayed when the student fails - makes three mistakes
    public bool inputIsCorrect = false;
    public string currentAns;

    public GameObject UI2;

    void checkInput(TMP_InputField input, string currentAns) //checks the player's input, takes in the input and the current answer to compare them
    {
        input.text = input.text.Replace(" ", ""); //replaces any white spaces in the input text

        if (input.text == currentAns)
        {
            inputIsCorrect = true;
            Debug.Log("Correct answer");
            inputBox.text = ""; //empties the input box

        }
        else
        {
            Debug.Log("Wrong answer");
            inputBox.text = "";
        }
    }
    public void part2(int wrongCounter) //part 2 - wordy question - takes in the wrongCounter value
    {
        Debug.Log("Part 2");
        inputIsCorrect = false;
        QTxt.text = P2Question;
        currentAns = P2Answer;

        inputBox.onEndEdit.AddListener(delegate { checkInput(inputBox, currentAns); }); //adds a listener to check the input box value after the player's edit

        if (inputIsCorrect)
        {
            part3(wrongCounter); //calls part 3 , passing in the wrongCounter value
           

        }
        else
        {
            wrongCounter++; //increments wrongCounter
            part3(wrongCounter); //calls part 3 even if answer is wrong

        }
    }

    void part3(int wrongCounter)
    {
        Debug.Log("Part 3");
        inputIsCorrect = false;
        QTxt.text = P3Question;
        currentAns = P3Answer;

        inputBox.onEndEdit.AddListener(delegate { checkInput(inputBox, currentAns); });

        if (inputIsCorrect)
        {
            winOverlay.SetActive(!winOverlay.activeSelf); //if answer is correct, displays the win overlay which'll contain the score and award
        }
        else
        {
            wrongCounter++; //increments the wrongCounter
            if (wrongCounter == 3) //if the student fails all three questions
            {
                UI2.SetActive(!UI2.activeSelf); //the UI is deactivated
                failOverlay.SetActive(!failOverlay.activeSelf); //the fail overlay is activated
            }
            else //if they get at least one question right
            {
                UI2.SetActive(!UI2.activeSelf); //the UI deactivates
                winOverlay.SetActive(!winOverlay.activeSelf); //the win overlay is activated
            }
        }
    }
   
}

My issue is that when I press any of the choices for the multichoice questions (and it does fine on detecting whether the chosen answer is correct or not), it starts part 2 but starts part 3 immediately after it (I noted that because I’ve added a Debug.Log to both parts with the name of the part and noted in the log that they come at the exact same time after choosing the answer). When the chosen answer for the multichoice question is correct, it immediately activates the winOverlay line at the end of the last script, and if not, it displays the failOverlay instead. Initially, I had it so that the isCorrect boolean is used for both scripts, but I thought that that might be the reason that once the first question is done, the next two are called at the same time, so I changed it to inputIsCorrect, but that didn’t change anything. I then duplicated the input box used for parts 2 and 3 and added a new UI3 object but that didn’t change anything, so I reverted to having one input box for both parts.
The issue looks like this when I press the button: When button is pressed - Album on Imgur
What could be causing this? I’ll be thankful for any help, thank you very much :sweat_smile:

Drop a breakpoint, no one wants to wade through 150 lines of code.

1 Like

You’re adding an event listener but I don’t see anywhere in your code that you’re removing it again. Unless you’re disposing of the InputBox after every part the listeners are just going to keep piling onto the event causing multiple calls to checkInput every time it fires.

inputBox.onEndEdit.AddListener(delegate { checkInput(inputBox, currentAns);
2 Likes

I wasn’t aware I had to do that :roll_eyes: But anyways, I tried removing the listener by using this

inputBox.onEndEdit.RemoveListener(delegate { checkInput(inputBox, currentAns); });

But it didn’t change anything, the issue still persists :frowning:

Sorry about that my brain apparently derped out and I forgot to mention you can’t use an anonymous delegate.

inputBox.onEndEdit.AddListener(OnEndEdit);
inputBox.onEndEdit.RemoveListener(OnEndEdit);

private void OnEndEdit(string userInput) => checkInput(inputBox, userInput);
1 Like

Sorry, but I don’t understand what the => notation means? I looked online but found only one thread and it gave me an error when I tried to replicate it

Oh, it’s apparently expecting a different parameter than a string. Serves me right for not looking at the docs before posting. :sweat_smile:

private void OnEndEdit(InputField userInput) => checkInput(inputBox, userInput.text);

In this case it’s syntactic sugar for this. I like my scripts to fit within a single screen and that symbol is one of the ways you can do it.

private void OnEndEdit(InputField userInput)
{
    checkInput(inputBox, userInput.text);
}

Hopefully this solves it and I didn’t forget something else. :stuck_out_tongue:

1 Like

Thank you! I did what you said, and kept the checkInput method as it is

private void OnEndEdit(TMP_InputField userInput)
{
    checkInput(inputBox, userInput.text);
}

void checkInput(TMP_InputField input, string currentAns)
{
    ...
}

but it hit me with a dozen errors for everytime the OnEndEdit method is used for listeners in the script!
Argument 1: cannot convert from 'method group' to 'UnityEngine.Events.UnityAction<string>'
I tried changing the void checkInput method’s parameters to match the ones in OnEndEdit but it hit me with more errors so I changed it back to how you told me to do it