Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Bug Coroutine not passing value of an int variable correctly through an Action parameter.

Discussion in 'Scripting' started by Spheniac, May 15, 2024.

  1. Spheniac

    Spheniac

    Joined:
    Dec 5, 2023
    Posts:
    1
    Hello. I've been following tutorials to learn unity and C#. Following a tutorial I've implemented a system that shows the player a choice box. The choice box works fine as implemented in the tutorial, but when I want to expand this into other game scenarios it does not work. This is the implementation of the code that doesn't work:
    Code (CSharp):
    1.     public void HandleUpdate(Action<int> onSelected)
    2.     {
    3.         if (choosing)
    4.         {
    5.             if (Input.GetKeyDown(KeyCode.DownArrow))
    6.                 currentSlot += 2;
    7.             else if (Input.GetKeyDown(KeyCode.UpArrow))
    8.                 currentSlot -= 2;
    9.             else if (Input.GetKeyDown(KeyCode.LeftArrow))
    10.                 --currentSlot;
    11.             else if (Input.GetKeyDown(KeyCode.RightArrow))
    12.                 ++currentSlot;
    13.         }
    14.  
    15.         currentSlot = Mathf.Clamp(currentSlot, 0, Moves.Count);
    16.  
    17.         UpdateMoveSelection(currentSlot);
    18.  
    19.         if (Input.GetKeyDown(KeyCode.Z))
    20.         {
    21.             StartCoroutine(Confirm(onSelected));
    22.         }
    23.     }
    24.  
    25.     IEnumerator Confirm(Action<int> onSelected)
    26.     {
    27.         int selectedChoice = 0;
    28.         choosing = false;
    29.  
    30.         yield return choiceBox.ShowChoices(new List<string>() { "Yes", "No" }, (choiceIndex) => selectedChoice = choiceIndex);
    31.  
    32.         if (selectedChoice == 0)
    33.         {
    34.             // Yes, continue
    35.             choosingMove = true;
    36.             onSelected?.Invoke(currentSlot);
    37.         }
    38.         else if (selectedChoice == 1)
    39.         {
    40.             // No, go back
    41.             SetMessageText("Which move should be forgotten?");
    42.             choosing = true;
    43.             yield break;
    44.         }
    45.     }
    And this is the choice box scritp:
    Code (CSharp):
    1. public IEnumerator ShowChoices(List<string> choices, Action<int> onChoiceSelected)
    2. {
    3.     gameObject.SetActive(true);
    4.     choiceSelected = false;
    5.     currentChoice = 0;
    6.     choiceTexts = new List<ChoiceText>();
    7.  
    8.     // Delete existing choices
    9.     foreach (Transform child in transform)
    10.     {
    11.         Destroy(child.gameObject);
    12.     }
    13.  
    14.     // Instantiate new choices
    15.     foreach (var choice in choices)
    16.     {
    17.         var choiceTextObj = Instantiate(choiceTextPrefab, transform);
    18.         choiceTextObj.TextField.text = choice;
    19.         choiceTexts.Add(choiceTextObj);
    20.     }
    21.  
    22.     yield return new WaitUntil(() => choiceSelected == true);
    23.  
    24.     onChoiceSelected?.Invoke(currentChoice);
    25.     gameObject.SetActive(false);
    26. }
    27.  
    28. private void Update()
    29. {
    30.     if (Input.GetKeyDown(KeyCode.DownArrow))
    31.         ++currentChoice;
    32.     else if (Input.GetKeyDown(KeyCode.UpArrow))
    33.         --currentChoice;
    34.  
    35.     currentChoice = Mathf.Clamp(currentChoice, 0, choiceTexts.Count - 1);
    36.  
    37.     for (int i = 0; i < choiceTexts.Count; i++)
    38.     {
    39.         choiceTexts[i].SetSelected(i == currentChoice);
    40.     }
    41.  
    42.     if (Input.GetKeyDown(KeyCode.Z))
    43.     {
    44.         choiceSelected = true;
    45.     }
    46. }
    For some reason that I don't understand, when the ShowChoices Coroutine ends the value that the Action passes through the choiceIndex parameter to the selectedChoice variable is always 0, so no mather what the player selects, only the first option gets executed.
    I tried debugging and the currentChoice variable that controls which option is selected and is passed through the Action does work and its value changes between 0 and 1 as intended. I tried forcing the selectedChoice variable that triggers the Action to 1 and its value does change to 0.
    Can someone please explain to me why does it happen and how can I solve it? I feel like I'm overseeing something stupid that I just can't find.
    Thank you.