Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
1
Question by Cirrocumulus · Feb 03, 2018 at 09:13 PM · uicanvas

How to reference the Canvas

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);
     }
 }


Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Owen-Reynolds · Feb 03, 2018 at 09:16 PM 0
Share

Canvas. As in: public Canvas C;

avatar image Cirrocumulus Owen-Reynolds · Feb 03, 2018 at 09:17 PM 0
Share

First thing I tried. Doesn't work.

avatar image Owen-Reynolds · Feb 04, 2018 at 04:08 PM 1
Share

Ah..."the prefab." There's your problem. Those can't store references to anything in a Scene. Search for Qs on this for more.

avatar image Cirrocumulus Owen-Reynolds · Feb 04, 2018 at 04:42 PM 0
Share

I have, like I wrote above. Does this mean that if I want to reference the Canvas then I have to instantiate it (and my whole UI) from code? It's possible of course, but it seems like it beats the point of having a visual editor in the first place.

2 Replies

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by ElijahShadbolt · Feb 04, 2018 at 08:41 PM

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".

Add Tag


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;

capture.png (13.3 kB)
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Cirrocumulus · Feb 04, 2018 at 08:51 PM 2
Share

Thank you. Like I wrote, I was hoping to avoid using finding by strings (like FindGameObjectWithTag), because I am instantiating Text objects at runtime (whenever an enemy is hit, a score value is displayed at its transform position), and from what I've read this is an expensive call to make. But I guess that if I cache it in the class instantiating the Text object then I should be O$$anonymous$$. The singleton approach seems like a lot for a rather simple purpose, but thanks a lot for both ideas.

EDIT: Actually, I remember now why I didn't want to use "Find" methods. The gameObject I'm intending to put this component on is itself instantiated and destroyed regularly (not every second, but still). And I'd really like to avoid slow method calls if I can. I've already manage to work around the problem with a completely different approach (UI$$anonymous$$anager with event subscription and an interface). I was just hoping to convert this into a component so I could just plug it where I need it without implementing the interface every time. Anyway, thanks again.

avatar image ElijahShadbolt Cirrocumulus · Feb 04, 2018 at 09:16 PM 0
Share

I'm glad I could assist you in finding a solution that best meets your needs!

avatar image Harinezumi Cirrocumulus · Feb 06, 2018 at 08:40 AM 0
Share

@Cresspresso 's answer is really good, tagging and singleton are the best approaches to this. $$anonymous$$y question is though: why do you destroy and create the Canvas all the time? Why not just create a Canvas once, name it something meaningful ("DamageUI"?), and then leave it in the scene? $$anonymous$$eaning, is there a reason to destroy it? Or if there is, could you circumvent that reason in a way that the whole system works cleaner?

avatar image ElijahShadbolt Harinezumi · Feb 06, 2018 at 09:09 PM 1
Share

I suggest that the Canvas element stays in the scene and is not destroyed at any point. Text elements instantiated as children of the canvas would work fine, and is a good technique for stuff like enemy markers and health bars. You may never know how many enemies will be in the scene, so you will need to make more markers at runtime. I never said to destroy or replace the canvas, just that when the Text elements are instantiated, you should fix their null reference to the canvas in the scene.

Show more comments
avatar image
-1

Answer by Hamburgert · Feb 04, 2018 at 11:58 AM

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.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Cirrocumulus · Feb 04, 2018 at 02:16 PM 1
Share

Thanks. I'm sorry but I've tried that a zillion times, and one more time after reading your post. The prefab clearly shows a field called "Canvas" with "None (Rect Transform)" in it. I can drag the Canvas object from the hierarchy as much as I want, it won't register. It's like dragging a a sound clip into a GameObject field.

avatar image Harinezumi · Feb 06, 2018 at 08:41 AM 0
Share

Prefabs cannot have references to scene objects, and this prefab is instantiated during the game, so you cannot "drag and drop in the Editor".

avatar image Hamburgert Harinezumi · Feb 06, 2018 at 12:10 PM 0
Share

Prefabs are, however, fully capable of referencing parts of themselves. Of course, if the Canvas is not part of the prefab, then that is where I misunderstood the question.

avatar image Harinezumi Hamburgert · Feb 06, 2018 at 12:17 PM 0
Share

You are right, prefabs can reference themselves, so if the prefab has a Canvas on it, then it can be referenced (dragged onto the Text component). However, if I understood it correctly, even the Canvas is instantiated run-time, so I think it is not part of the prefab.

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

133 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Possible for 10 canvas in 1 scene? 1 Answer

Dark UI canvas isssue 0 Answers

Need help with shield bar enable and disable. 0 Answers

Hard crash when enabling/disabling UI elements 4 Answers

How to find an UI button by name? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges