Been going crazy here after one hour of googling and reading all I could find on this forum about the subject. I’m instantiating a Text object from a script on a prefab, and in order to be visible the Text has to be parented to the Canvas object in the scene. But in my script, I can find no way of getting a reference to the Canvas (short of using GameObject.Find which I don’t want to use). No public variable allows dragging the Canvas from the scene onto the public field (be it Canvas, GameObject, Transform, or RectTransform). What am I doing wrong?
using UnityEngine;
using UnityEngine.UI;
public class DisplayPointsAtScreenPosition : MonoBehaviour {
public Canvas canvas;
public Text UITextObject;
public void DisplayPoints(string text)
{
Text t = Instantiate(UITextObject);
t.transform.SetParent(canvas.transform, false);
t.transform.position = Camera.main.WorldToScreenPoint(gameObject.transform.position);
t.text = text;
Destroy(t, 1.0f);
}
}
Prefabs cannot store references to scene objects, only other prefabs or assets. When you instantiate the Text object, you must assign scene-specific references then.
Option 1: Tags
Give your canvas GameObject the tag “MainCanvas”.
When initializing your Text object
canvas = GameObject.FindGameObjectWithTag("MainCanvas").GetComponent<Canvas>();
Option 2: Singleton Class
Keep all of your scene references in one class instance in the scene.
public class ReferenceHub : MonoBehaviour {
// singleton static reference
private static ReferenceHub _Instance;
public static ReferenceHub Instance {
get {
if (_Instance == null) {
_Instance = FindObjectOfType<ReferenceHub>();
if (_Instance == null)
Debug.LogError("There is no ReferenceHub in the scene!");
}
return _Instance;
}
}
// assign this in the inspector
[SerializeField]
private Canvas _mainCanvas;
public Canvas MainCanvas { get { return _mainCanvas; } }
// _mainCanvas field is private with a public getter property to ensure it is read-only.
}
When initializing your Text object
canvas = ReferenceHub.Instance.MainCanvas;
It may be easier to work with the canvas transform. Rather use:
public RectTransform canvas;
Now you can drag-n-drop the canvas in the editor, and it will automatically now reference the transform. Remember to make a change in your DisplayPoints from canvas.transform to just canvas.
public void DisplayPoints(string text)
{
Text t = Instantiate(UITextObject);
t.transform.SetParent(canvas, false); // Also change this
t.transform.position = Camera.main.WorldToScreenPoint(gameObject.transform.position);
t.text = text;
Destroy(t, 1.0f);
}
An alternate way of doing it may be to add the Text at the correct position in the editor, then disable it. In your script you can then simply to t.gameObject.SetActive(true) instead of instantiating.