- Home /
Unable to attach script to GameObject prefab at runtime
I've got a script that manages a scene browser within my application where I'm hoping to generate a new button instance for each scene found. I've put together a button that I've made into a prefab and everything works up until I try to attach click behavior to the button. So far I am unable to capture or attach anything to the "onClick()" piece of the button component no matter what I try.
Code is as follows:
MySceneBrowser.cs
foreach(string sceneName in sceneList){
GameObject sceneButton = Instantiate(SceneButton) as GameObject;
// Attach the scene name to the nested text UI object of the button
sceneButton.GetComponentInChildren<Text>().text = sceneName;
/* Where I hope to attach script and method with parameter, method is within
* this class and called LoadSelectedScene(string sceneName)
*/
sceneButton.transform.SetParent(SceneListPanel, false);
}
Where in the inspector SceneButton is assigned to the prefab I've created, SceneListPanel is set to a content panel, and the scene list is generated in another method.
Any attempt I make to get the button component and allow me to set the onclick() fails, it just doesn't seem to exist through the script editor.
Setting any of these items through the inspector works, but I can't assign my controller class to the prefab before RunTime. I tried attaching a script directly to the prefab, but in this case only MonoBehavior functions were present through the inspector and I was unable to find any other method.
Once I attach the script I also need to be able to add the sceneName as the parameter.
[Edit] DMGregory pointed out I didn't elaborate on what I've tried so far, at this time I've tried the following (likely very wrong, still new to Unity) attempts to attach the desired script method:
sceneButton.AddComponent< SceneBrowserController >().LoadSelectedScene(sceneName);
Button b = sceneButton.GetComponent< Button >(); b.OnClick()...<--- Script can't find onClick, doesn't exist, doesn't show it as an option in code completion, etc.
sceneButton.AddComponent< SceneBrowserController >.LoadSelectedScene(sceneName); <-- obviously doesn't add it to the onClick listener, just attaches the script
SceneButton.AddComponent< UIEventListener >()....
UIEventListener.Get(sceneButton).onClick().....
This is in general the attempts I've made so far, with some variation. I don't have all my old attempts saved unfortunately. I'm sure I'm making a newbie assumption/mistake somewhere.
[Update] While playing with the prefab through my script I went ahead and tried this out:
if(sceneButton.GetComponent< Button >()){
Debug.Log("This object is here");
}
and it returns false on the if, if I change the if to (!sceneButton.GetComponent()) it does show the log message. To my understanding this indicates the button game object is not found, yet it is a component on the top level of the prefab.
[Update 2] Can anyone explain why this doesn't work to attach the onclick listener?
sceneButton.GetComponentInChildren<Button>().OnClick.AddListener(() => LoadSelectedScene(scene));
Gives the following compiler error:
Assets/.../.../.../SceneBrowser.cs(347,68): error CS1061: Type `Button' does not contain a definition for `OnClick' and no extension method `OnClick' of type `Button' could be found (are you missing a using directive or an assembly reference?)
[Update 3] As close to showing my full code as possible:
using UnityEngine;
using UnityEngine.UI;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class MyFileBrowser : MonoBehaviour
{
Public GameObject SceneButton; // This is assigned to the prefab in inspector, they render properly.
[...]
public void LoadSelectedScene(string sceneName){
// This is the method I'm hoping to reference in the onClick listener, while passing it the scene name
}
[...]
private void DisplaySceneList(string[] scenesOutput){
foreach(string sceneName in sceneList){
GameObject sceneButton = Instantiate(SceneButton) as GameObject;
// Attach the scene name to the nested text UI object of the button
sceneButton.GetComponentInChildren<Text>().text = sceneName;
/* Where I hope to attach script and method with parameter, method is within
* this class and called LoadSelectedScene(string sceneName)
*/
// Current attempt:
sceneButton.GetComponent<Button>().onClick.AddListener(() => LoadSelectedScene(sceneName));
// The onClick.AddListener[...] is all red in MonoDevelop, hover message says "'Button' does not contain a definition for 'onClick'
sceneButton.transform.SetParent(SceneListPanel, false);
}
}
This is with a prefab with the following structure:
SceneBrowser_SceneSelectButton (Image Component, Button Component, Layout Element Component)
Scene Image (Image component w/ sprite)
Scene Label (Text component)
I can access the Scene label no trouble with "GetComponentInChildren< Text >.text [...]" but cannot get "GetComponent< Button > on the sceneButton object created from this prefab. Oddly, "GetComponent< Image > does capture the image component off the top level object just fine.
Direct question here, why doesn't this call work , everything onClick and forward is in red. I've added a new button object as a child on the prefab so it should find that the way it did when I pulled up text (Shown in the original question)
sceneButton.GetComponentInChildren<Button>().onClick.AddListener(() => LoadSelectedScene(sceneName));
This is a good tutorial for making UIs and buttons dynamic each video is short and comes together i think watching the first 4 will cover your issue
I just tried the following in a scene with a camera, canvas, and eventsystem in addition to a button prefab in my /Resources folder and it worked for me.
using UnityEngine;
using UnityEngine.UI;
using System;
public class $$anonymous$$yFileBrowser : $$anonymous$$onoBehaviour
{
public GameObject SceneButton;
void Start(){
DisplaySceneList(new string[1]{"scene1"});
}
public void LoadSelectedScene(string sceneName){
Debug.Log(sceneName);
}
private void DisplaySceneList(string[] scenesOutput){
foreach(string sceneName in scenesOutput){
GameObject sceneButton = Instantiate(SceneButton) as GameObject;
sceneButton.GetComponentInChildren<UnityEngine.UI.Text>().text=sceneName;
sceneButton.GetComponent<Button>().onClick.AddListener(() => LoadSelectedScene(sceneName));
sceneButton.transform.SetParent(transform, false);
}
}
}