Search Unity

Dynamically create button listeners with parameter passing.

Discussion in 'Scripting' started by trilobytes, Sep 21, 2020.

  1. trilobytes

    trilobytes

    Joined:
    Sep 13, 2020
    Posts:
    3
    I want to have a create a pop-up menu which lists the player's inventory (as buttons) and when one is selected, that item is spawned.

    To create the buttons I iterate over the player's inventory but I'm not sure how to add a listener to each button so that the correct item is passed to the spawner class as a parameter?

    I am also open to alternative methods of achieving this goal.

    Code (CSharp):
    1. private void CreateButtons()
    2.     {
    3.         presentedButtons = new List<UnityEngine.UI.Button>();
    4.  
    5.         for (int i = 0; i < inventoryToDisplay.Container.ItemLines.Count; i++)
    6.         {
    7.             presentedButtons.Add(Instantiate(ButtonPrefab, new Vector3(XStartPosition, YStartPosition - (i * YSpaceBetweenRows), 0), Quaternion.identity));
    8.             presentedButtons[i].transform.SetParent(GetComponent<RectTransform>(), false);
    9.             TMP_Text txt = presentedButtons[i].GetComponentInChildren<TMP_Text>();
    10.             txt.text = inventoryToDisplay.Container.ItemLines[i].item.Name + " (" + inventoryToDisplay.Container.ItemLines[i].amount + ")";
    11.  
    12.             presentedButtons[i].onClick.AddListener(() => {
    13.                 _spawner.testButtonPress(inventoryToDisplay.Container.ItemLines[i].item);
    14.             });
    15.         }
    16.     }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    You're almost there... the above is likely perfect EXCEPT that C# does "variable capture" instead of value capture.

    This means that your listeners will ALL be created and use the final value of
    i
    , not an ever-increasing 0, 1, 2, 3 etc which is what you want.

    SO... what you want to do is make a local variable inside the
    for()
    loop block:

    Code (csharp):
    1. int i2 = i;   // capture for delegate
    And now use
    i2
    anywhere in the delegate. Each time through the loop that is a brand-new instance of the local variable, each one containing 0, 1, 2, 3, 4, etc. and "captured" individually by the C# delegate.
     
    bisewski, Vana, Dimorian and 2 others like this.
  3. trilobytes

    trilobytes

    Joined:
    Sep 13, 2020
    Posts:
    3
    This solved the problem. Thank you.
     
    Kurt-Dekker likes this.