- Home /
References to scene objects in prefabs - Inspector vs. Find
Hello all,
I feel like beeing in an endless loop...
I have a LevelUIManager holding a reference to a text UI object "txt_currentSpeed".
public class LevelUIManager : MonoBehaviour {
public Text txt_Distance;
...
My first approach was to use the inspector to bind the text object to the public field of my LevelUIManager class.
My LevelUIManager is a prefab in order to use it in every level and with this approach I was facing the problem that the references were not working when reusing this prefab in different scenes and after some research I found out that it is not possible to reference scene objects from a prefab. Okay, that's a pity, but the solution I found everywhere was "use GameObjects.Find()" to get the reference.
...
Okay, hence, my second approach looks like this:
private GameObject completeLevelUI;
private Text txt_Distance;
private void Start()
{
txt_Distance = GameObject.Find("txt_Distance").GetComponent<Text>();
completeLevelUI = GameObject.Find("LevelComplete");
While getting the txt_Distance reference works fine, getting the LevelComplete reference does not work since it is a panel which I disabled in order to active it when I need it.
Doing some research again brought up lots results which say: "Find() is always the worst method to use to get a reference, use the inspector instead"
...
GREAT, now I am at the beginning again...
That is the point where I want to ask you to explain me, which is a meaningful way to deal with my issues.
When can / should I use the inspector method
When can / should I use find()
What is a good way to get a reference to a disabled object
Thanks in advance!
Answer by Aluminum18 · Apr 20, 2021 at 03:34 AM
You are right that an object from scene cannot be referenced by a Prefab. In your case, the solution is: create LevelUIManager in the scene and its references would be its children. Then you can drag LevelUIManager to your asset as prefab. Now you can use this prefab in several scene without reference problem.
Avoid Find() if you can. Behind the scene, Unity iterates through all objects in the scene to find the object(s). If your scene is large, using Find() costs a lot of overhead to your CPU. In other hand, using Find() creates "Hidden logic", it means some objects are depend on some objects but you cannot see those dependencies in Unity Editor. I think, the best use case for Find() is when you want to quick test your logic while coding.When can / should I use find()
Use Inspector.What is a good way to get a reference to a disabled object
Use Inspector if you can. Inspector is a very powerful tool, it can be a Dependency Injector, a Debugger or even a Design Tool for Game Designer. It is the connect point of all roles in a team (Programmer, Game Designer or Artist would get better view of project structure if the game logic is present well in the Inspector)When can / should I use the inspector method
Thanks @Alu$$anonymous$$um18 for your reply.
I still do not understand the general logic of prefabs and reference. When is what allowed or not allowed and why? I really would like to understand the general rules in order to avoid future problems with similar constallations.
Does it only depend whether something is a child of a gameobject or not?
.
So, would this example work:
+ prefabHavingChildToReference
+++ txt_ICanBeUsedByParentWithoutAnyProblem
.
And this won't work:
+ prefabWithoutChild
+ txt_ICantBeUsedWithinAPrefab
??
If object A wants to reference object B, A needs to know where B is (or B Address).
In Unity, an Object in Scene has Address of all other objects in this Scene (not other Scene) and all objects in Assets folder.
A prefab, in an other hand, just has Address of its children and objects in Assets folder.
This is the reason why in your case, we have to create LevelUIManager prefab which contains txt_Distance as its child for reference.
Note: Do not confuse Prefab and Prefab instance. When you drag a Prefab from Assets folder and drop it into Scene, an object (with blue color) will be created in Scene. It is a Prefab instance which will update every change from Prefab and is also an Object in Scene.
okay, I see. Thank you for the explanation! For the example above the approach of using the txt object as a child works fine, since both belong together from a contextual perspective anyway.
.
However, I am still wondering what the best / easiest way is to deal with prefabs and references in general. What goes through my $$anonymous$$d is, that there will be many cases where I have prefabs which have to have references to other prefabs/objects which do not belong together and hence I cannot always set them as a child.
.
Don't know, take a Player object. And you have a GameManager and AnotherObject which both need a reference to Player. Here I need another meaningful way so that both can get a reference in the prefab with setting it manually each time after creating a prefab instance.
It's a quite big question :). It is how you structure your project architecture. A common way is using ScriptableObject. You can take a look at this talk. A long talk but gold. I do believe that after retrieve the ideal from this talk, you can find a solution for this problem.However, I am still wondering what the best / easiest way is to deal with prefabs and references in general. What goes through my $$anonymous$$d is, that there will be many cases where I have prefabs which have to have references to other prefabs/objects which do not belong together and hence I cannot always set them as a child.
Read below answer after you understand the talk above ;). This is my solution using ScriptableObject (call it SO for now)
Usually, for the code is more flexible, object often just references what it needs. Assu$$anonymous$$g in above example, GameManager just needs the Player HP (hit point) and AnotherObject just needs Player position. We can creates 2 SOs, one holds Player HP and other holds Player Transform. GameManager and AnotherObject should reference to the SO that holds information they need. Or in case your GameManager needs to call a method from Player? You can use SO event (detail in above talk), GameManager raises an event and Player listens to execute wanted method.Don't know, take a Player object. And you have a GameManager and AnotherObject which both need a reference to Player. Here I need another meaningful way so that both can get a reference in the prefab with setting it manually each time after creating a prefab instance.