I have a U.I panel with a text component child saved as prefab. I want to instantiate said prefab but apparently I cannot use GameObject.Find for in inactive objects(?) so it is returning a null.
Yes, I know if I made it a public field it would solve the problem but I would like to use public fields only when necessary.
I have seen some workarounds like keeping the original panel in the hierarchy then switching it to inactive upon starting.
Before I submit to public fields or workarounds; Is there no way to store a reference of an inactive object?
Instantiate() returns you the reference to the instantiated object. You store references to inactive objects in the same way you store references to active objects. Both are just normal (C#) references after all. Being active or inactive is a property of the referenced object, which is a Unity specific thing.
Also, try to stay away from GameObject.Find() in the first place. Itâs slow and basically only intended for quick prototyping. It never has to be used, so really it never should unless you know about that and still decide to use it.
As i already described, if you use Instantiate(), it returns you the reference to the instantiated object.
Other than that, you can manually assign references through the inspector if the object exists outside runtime. By the way, such a field does not have to be public. It has to be serialized. Public just serializes a field by default, but from an architectural viewpoint, youâd most often want to use [SerializeField] private, instead of public (if all you need it for is for it to show up in the inspector, and not actually need it to be public).
One other way to get a reference is to get it from another object which knows the reference.
So basically you can get a reference in these ways:
Create the object yourself,
get the reference from some other object that has it, and to which you have a reference,
When I say i donât want use public fields, I really mean I do not want to use any of the âdrag n drop in the inspectorâ routes unless necessary. What does the bold mean?I cant instantiate the object because its not stored, its not stored because I cant make a reference to it⌠because its inactive, ignoring using public and serialized fieldsâŚwhich I donât want to
In this case the Canvas would be the parent when it is instantiated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChangeName : MonoBehaviour
{
Text text;
GameObject panel;
Canvas canvas;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void NameChanger()
{
canvas = GetComponent<Canvas>();
if (canvas != null)
{
panel = canvas.transform.Find("NameTag");
text = panel.GetComponentInChildren<Text>();
text.text = "hi";
}
}
}
Gives me I cant convert unityengine. transfrom to unityengine.gameobject error.
You need to make the panel a Transform not a GameObject.
using UnityEngine;
using UnityEngine.UI;
public class ChangeName : MonoBehaviour {
Text text;
Transform panel; // MAKE THIS Transform INSTEAD OF GameObject
GameObject canvas;
// Start is called before the first frame update
void Start() {
}
void Update (){
}
public void NameChanger() {
canvas = GameObject.Find("Canvas");
if (canvas != null) {
panel = canvas.transform.Find("NameTag");
text = panel.GetComponentInChildren<Text>();
text.text = "hi";
}
}
}
Your code is overly complex though. Do this instead:
using UnityEngine;
using UnityEngine.UI;
public class ChangeName : MonoBehaviour {
// Make this public and assign it in the editor
// ALSO: You don't event have to disable the text object at all. Just set text.text = ""
public Text text;
public void NameChanger() {
text.text = "hi";
}
}
Lololololol. Guuuuys! I am well that If I assigned them the inspector this thread would not even be here. I want to learn to program using the âdrag into inspectorâ only when necessary.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChangeName : MonoBehaviour
{
Text text;
public Transform panel;
Canvas canvas;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public void NameChanger()
{
GameObject holder = GameObject.Find("Canvas");
if (holder != null)
{
canvas = holder.GetComponent<Canvas>();
panel = canvas.transform.Find("NameTag");
text = panel.GetComponentInChildren<Text>();
text.text = "hi";
}
}
}
Now here is the code that is doing the instantiating:
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class Spawn : MonoBehaviour
{
ChangeName changeName;
Transform bar;
GameObject spot;
Transform Position;
// Start is called before the first frame update
void Start()
{
changeName = GetComponent<ChangeName>();
//bar = changeName.panel;
spot = GameObject.Find("Spot");
MakeThing();
}
// Update is called once per frame
void Update()
{
}
public void MakeThing()
{
bar = changeName.panel;
Transform Position = spot.transform;
Transform HUD = Instantiate(bar, Position.position, Position.rotation);
HUD.transform.SetParent(GameObject.Find("Canvas").transform,false);
HUD.transform.position = Position.position;
changeName.NameChanger();
}
}
its saying the bar = changeName.panel is is not set to instance of object. Again its tring to instantiate a object that is not being referenced. Its wants to know what panel is, panel is going to be the currently inactive prefab.
Youâre calling changeName.panel before panel is set. Panel is set when you call changeName.NameChanger() . Call changeName.NameChanger() before calling bar = changeName.panel
changeName.NameChanger();
bar = changeName.panel;
Transform Position = spot.transform;
Transform HUD = Instantiate(bar, Position.position, Position.rotation);
HUD.transform.SetParent(GameObject.Find("Canvas").transform,false);
HUD.transform.position = Position.position;
Try to follow the methods in your code manually in your head so you can better understand what order things are happening in.
Iline 5 that is where the UI panel is instantiated
6. it is childed to canvas
7. put into positon
then i want to change text with Namechanger()
If I do namechanger() first it tries to change the name of an object not yet instantiated⌠that would not be an issue if I could access the text component of panel, but I cant⌠because I cant make a reference to it, because it is currently inactive.
If you want to work without it, go look for another engine. Sorry if this seems rude, but you are effectively asking how to do something without using a tool, in a forum dedicated to answering questions about said tool.
You can always write code without Unity. There you get references only by either directly creating the object, or passing it around between objects. It also took me some time to get used to the Unity workflow, but thatâs how it is.
If you want to instantiate a prefab, you need a reference to the prefab. You can get this either by dragging the prefab in through the inspector, or load the ressource based on its name. The latter is whatâs actually bad design, since the programm breaks as soon as the file gets renamed.
Honestly tho, just try to see the inspector inputs as the launch parameters of your program. Itâs not that different from normal programms, where you can give it launch parameters to alter its behavior through the console, or possibly some settings. You are just determining the looks and relations of the software you write, by altering its input parameters.
So for all intents and purposes, the âdrag into inspectorâ part is necessary for referencing the prefab. I have the feeling you think about this as âcheatingâ somehow, and believe it makes you a worse programmer. If thatâs the case, improve your confidence by writing a normal object oriented application outside of Unity or any other engine. From scratch up. Then you know you can do it âthe normal wayâ. Afterwards ask yourself: does it make you a better or worse programmer to intentionally use a slower, worse way (loading with Find() or from ressources for example), simply because you do not want to use the intended fast way.
Working with the editor is very difficult when you are working in a big team and your code has to go through code review (you cannot easily code review Scenes.) Also usually you do not have all the references in the scene yet, but they are being instantiated later when the whole application is brought up. The way we do this is to instantiate most of the Scene components from code and giving each system the needed references from there, this also helps with your references not going too crazy. although in some cases, there are static classes which can be referenced on the fly when an object is instantiated dynamically.
I think working in the editor is acceptable as long as the code is contained in one prefab, but outside of a prefab i would not use scene links for references.