- Home /
How to make On Click() work with prefabs?
Hi there,
I'm using a code that is working when I create objects in the scene, that I link to the on click() interface of the buttons. However when I create these objects as prefabs, and that I link everything between the prefabs, the code does not work anymore. I don't know if it is a bug or if it me who does not understand how the prefabs works. Here is the code:
public class OnClickAction : MonoBehaviour {
private GameObject activePanel;
void Start () {
activePanel = GameObject.Find ("Panel1");
activePanel.SetActive (true);
GameObject.Find("Panel2").SetActive (false);
}
public void DisplayP(GameObject panel){
activePanel.SetActive (false);
activePanel = panel;
activePanel.SetActive (true);
}
}
I have an empty gameobject "TestManager" to which this code is attached. On my scene I have a canvas, which hold 2 panels (panel1 with a "next" button and panel2 with a "back"). I attach to each button (via the interface of the button, in the On Click section) the gameobject "TestManager" and call DisplayP with the parameter of the other panel. It works fine as I said earlier when it is objects created directly in the scene. By clicking on the button, I switch panel and the code desactivate the panel not in use.
When I put my "TestManager" game object and my panels as prefabs, and then putting them back up to the scene from the prefab folder, it does not work anymore (though on the interface everything still looks fine, with the good references in the On click interfaces of the buttons). I have this error when I press the 1st button (to be noted that at least the code in Start() is working, as I have Panel1 activated, and Panel2 desactivated).
UnassignedReferenceException: The variable activePanel of OnClickAction has not been assigned. You probably need to assign the activePanel variable of the OnClickAction script in the inspector. OnClickAction.DisplayP (UnityEngine.GameObject panel) (at Assets/Scripts/OnClickAction.cs:15) UnityEngine.Events.InvokableCall`1[UnityEngine.GameObject].Invoke (System.Object[] args) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:180) UnityEngine.Events.CachedInvokableCall`1[UnityEngine.GameObject].Invoke (System.Object[] args) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:298) UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:626) UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:766) UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:54) UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35) UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44) UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52) UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269) UnityEngine.EventSystems.EventSystem:Update()
What I am doing wrong here? During play mode, if I reassign the "TestManager" and the panels that are in the scene to the onclick button, it works again, so I believe this means that the code was trying to call the prefab, rather than their instantiations. In my real code (here this is just a simple example), I did instantiation of the panels, and had the same problems. But I don't see how I could instantiate "TestManager" as everything starts from there basically. And this does not sound right to me that the prefab are being called (because then what is the point of doing a prefab?), so I wonder if this could be a bug.
Thanks in advance for your help, hope I've been clear enough!
Cheers
It seems that you are instantiating the prefab having many public gameObjects which you have dragged and dropped (from the project list and from the hierarchy list). If so, the problem here is that, on instantiating, unity prefab can only take the objects from the hierarchy list which are a prefab. (Note: the new prefab should also have these problems).
That is the reason, it works if you put the prefab after playing.
You could verify this by clicking the prefab which is instantiated. Its Public variable places will be null. Thus the option which I can suggest is :
1- to make all the necessary objects prefab (if count is less)
2- search with the name and include the object.
There may be more options. (I am not sure).
Happy coding.
@Rajeesh_AR Hello Rajeesh. Thank you for your answer. Regarding your points:
I don't have public gameOjects in my code but I do have objects (prefabs actually) linked to others via the button interface, yes. But I only associate prefab to each other, no object from the project hierarchy. Which mean that regarding your other point:It seems that you are instantiating the prefab having many public gameObjects which you have dragged and dropped (from the project list and from the hierarchy list). If so, the problem here is that, on instantiating, unity prefab can only take the objects from the hierarchy list which are a prefab. (Note: the new prefab should also have these problems).
You could verify this by clicking the prefab which is instantiated. Its Public variable places will be null.
This is not the case, my instances of prefabs do have the variables still there. But it does what I indicated in my above subject: it does not recognize the objects, despite they are there.
Any idea of what the problem could be?
Answer by dtumolo · Aug 31, 2017 at 11:39 PM
Prefabs can't access instantiated scene variables. So when you make it a prefab, it loses the ability to see the instances of the TestManager, and so the events have nothing to call. When you remap things in Play Mode, you are interacting with instances, so they can "see" again.
I'm struggling for a clean way around this for my game. Right now my plan is to not use prefabs for this piece. Another alternative is to initialize the OnClick listener in code. Both seem icky/not right.