Search code examples
unity-game-enginebuttononclickinspector

Get reference to a function to execute from the unity inspector for OnClick of a dynamically instantiated Button


I want to know how I can get a reference to a particular function on any another script through the unity inspector for adding it to a on-click listener of a dynamically instantiated button. I tried a public UnityEvent to get reference to the functions (just like in the onclick of a static button) but I am unsure how to add it to the on-click listener(button.onClick.AddListener(functionName)) as a listener looks for a action. Is there anything I am missing out ? Or is there any other approach to this? Thanks. This is the idea -

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

public class DynamicButton : MonoBehaviour
{
    public Button MainButton;
    public GameObject ButtonPrefab;

    [System.Serializable]
    public class ButtonInfo
    {
        public Sprite sprite;
        public UnityEvent ButtonEvent; //take reference to a particular function
    }
    public ButtonInfo[] ButtonCount;

    void Start()
    {
        PlaceButtons();

    }

    void PlaceButtons()
    {

        int NoButton = ButtonCount.Length;

        for (int i = 0; i < NoButton; i++)
        {           
            Vector3 newPos = new Vector3(i*10, i*10,0);   
            GameObject go = Instantiate(ButtonPrefab, newPos, Quaternion.identity);
            go.GetComponent<Image>().sprite = ButtonCount2To6[i].sprite;
            go.GetComponent<Button>().onClick.AddListener();  //This is where I want to add the  particular function that i want to execute when the button is clicked
            go.transform.parent = MainButton.transform;
            go.transform.localPosition = newPos;
        }
    }
}

Solution

  • What you have to do is Invoke the event instead of adding it to the onClick event. You don't have to find out / copy the listeners of each UnityEvent but instead invoking the UnityEvent is enough. The UnityEvent than calls all its listeners you assigned e.g. in the Inspector. This can be done by a simple lambda function:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Events;
    using UnityEngine.UI;
    
    public class DynamicButton : MonoBehaviour
    {
        public Button MainButton;
        public GameObject ButtonPrefab;
    
        [Serializable]
        public class ButtonInfo
        {
            public Sprite sprite;
            public UnityEvent ButtonEvent; //take reference to a particular function
        }
    
        public ButtonInfo[] ButtonCount;
    
        private void Start()
        {
            PlaceButtons();
        }
    
        private void PlaceButtons()
        {
            int NoButton = ButtonCount.Length;
    
            for (int i = 0; i < NoButton; i++)
            {           
                Vector3 newPos = new Vector3(i*10, i*10, 0);   
                GameObject go = Instantiate(ButtonPrefab, newPos, Quaternion.identity);
    
                // What is ButtonCount2To6?? It probably should rather be ButtonCount[i] ?
                go.GetComponent<Image>().sprite = ButtonCount2To6[i].sprite; 
    
    
                // since the lambda will have no acces to i you have to get the reference to the according ButtonInfo first
                var accordingButtonInfo = ButtonCount[i];
    
                // Add the Invoke call as lambda method to the buttons
                go.GetComponent<Button>().onClick.AddListener(() => {
                    accordingButtonInfo .ButtonEvent.Invoke();
                });  
    
                go.transform.parent = MainButton.transform;
                go.transform.localPosition = newPos;
            }
        }
    }
    

    see also this post