1

I load a Canvas prefab at runtime when an event occurs. The canvas simply has a Panel inside it, which in turn has 2 buttons. I'm trying to add OnClick events to both these buttons in the script, but it only works for the first button somehow! I have the following two lines of code one after the other:

GameObject.Find("RestartButton").GetComponent<Button>().onClick.AddListener(() => RestartClicked());
GameObject.Find("ViewButton").GetComponent<Button>().onClick.AddListener(() => ViewClicked());

The callback only works for the RestartButton, and not for the ViewButton. It may well be a very small thing, but I searched Google and Bing extensively and remain clueless, so any help would be appreciated.

Thanks!

Edit:

The script instantiates the prefab and tries to reference the two buttons in the prefab through GameObject.Find(), given that once Instantiate is called the Canvas should be active in the heirarchy. I also opened up the part of the code that attaches buttons to the listener for debugging. I dont think it attaches the listener at all.

void Start () {

    SetupScene();

    var prefab = Resources.Load("RestartOrViewPrefab");
    if (prefab == null)
    {
        Debug.LogAssertion("Prefab missing!");
        return;
    }
    restartCanvas = (GameObject)Instantiate(prefab);
    Button btn = GameObject.Find("ViewButton").GetComponent<Button>();
    btn.onClick.RemoveAllListeners();
    btn.onClick.AddListener(() => ViewToggle());
    Button btn2 = GameObject.Find("RestartButton").GetComponent<Button>();
    btn2.onClick.AddListener(() => RestartClicked());
}

private void RestartClicked()
{
    Debug.Log("RESTARTING");
    SetupScene();
}

private void ViewToggle()
{
    Debug.Log("TOGGLE");
    if (freshStart)
    {
        //Something here
        freshStart = false;
    }
    else
    {
        //Something else here
        freshStart = true;
    }
}
Kaizad Avari
  • 11
  • 1
  • 1
  • 7
  • I don't see anything wrong with your code. Can you post the rest of the code? Maybe there is something else happening that we don't know about – Programmer Jun 13 '16 at 19:29
  • Can you post the code of ViewClicked()? How do you determine if the callback does't work? – zwcloud Jun 14 '16 at 04:57
  • Sure. Sorry for posting just two lines of code. I thought the explanation would do justice. I'm updating my post. – Kaizad Avari Jun 14 '16 at 14:03

3 Answers3

0

So I took two days to solve my problem. Apparently, doing a GameObject.Find() for a GameObject within a prefab that you just instantiated doesn't work. We always need to use the GameObject that the Instantiate() method returns to find any component within the prefab. The code I used to make my scene work may not be the best solution if your prefab is very big/complex (say you have 15 buttons and need to do something with one), but it sure does work. :) I replaced the following lines of code:

Button btn = GameObject.Find("ViewButton").GetComponent<Button>();
btn.onClick.RemoveAllListeners();
btn.onClick.AddListener(() => ViewToggle());
Button btn2 = GameObject.Find("RestartButton").GetComponent<Button>();
btn2.onClick.AddListener(() => RestartClicked());

With the following lines of code:

Button[] buttons = restartCanvas.GetComponentsInChildren<Button>();

    foreach(Button but in buttons)
    {
        if(but.gameObject.name == "RestartButton")
            but.onClick.AddListener(() => RestartClicked());
        else if(but.gameObject.name == "ViewButton")
            but.onClick.AddListener(() => ViewToggle());
    }

So I just reused the restartCanvas that I got a reference to.

restartCanvas = (GameObject)Instantiate(prefab);

Hope this helps someone. :)

Kaizad Avari
  • 11
  • 1
  • 1
  • 7
  • after u instantiate the prefab just change its name , and I asked you are u getting any null reference or not but you did not reply – LumbusterTick Jun 17 '16 at 08:48
  • I did reply to your comment (see below). I was not getting any null references. How would changing the name of a prefab help though? Without changing the name, Unity could find the GameObjects I was looking for, but would not set or change any of their properties. – Kaizad Avari Jun 17 '16 at 14:56
  • just use this button mybutton = instantiate() , this way you eleiminate the need for find function and can use the same button to add onlick listener – LumbusterTick Jun 20 '16 at 08:03
0

I answered this on another post, but I'll answer it here for people that still need this info. The GameObject your instantiated button is a child of must have a CanvasRenderer component on it. I'm not sure why this works, but it does. Once the parent of the button GameObject has the CanvasRenderer on it, you can call myButton.onClick.AddListener(() => MyMethod(MyArgs)); as you normally would.

brosilio
  • 5
  • 2
-1

Ok make sure you are not getting any null reference error, and check tht spelling of you buttons , output some debug logs in your second function to see if its even reaching there

LumbusterTick
  • 1,067
  • 10
  • 21
  • I put debug logs, and its not reaching there. The weird part is that if I swap out the callbacks for Reset and View buttons, ViewClicked does get called by the ResetButton. Also, very rarely the ViewButton does start working and randomly stops working. I think the problem is with an EventHandler in the Canvas. Any suggestions? I'm going to post a more comprehensive view of the code so you can understand. Thanks again sir. – Kaizad Avari Jun 14 '16 at 14:01