I'm creating 2 GameObjects.
One automatically gets a RectTransform without explicitely adding one, the other doesn't.
In this case, a RectTransform isn't added, but it can be accessed:
GameObject nCanvasGO = new GameObject("CanvasContainer");
Canvas nCanvas = nCanvasGO.AddComponent<Canvas>();
nCanvas.renderMode = RenderMode.WorldSpace;
nCanvasGO.AddComponent<CanvasScaler>();
nCanvasGO.AddComponent<GraphicRaycaster>();
RectTransform rtCanvasGO = nCanvasGO.GetComponent<RectTransform>(); //can be accessed, isn't null
This one does not have a RectTransform:
GameObject nAnimInfo = new GameObject("AnimInfo");
RectTransform rtAnimInfo = nAnimInfo.GetComponent<RectTransform>(); // is null
I would therefore like to ask if adding a Canvas component to a GameObject add a RectTransform or what else might be the reason here.
Thank you.
Yes, Adding a canvas to a Gameobject will automatically change the Transform to a RectTransform. This is because the rect transform is the 2D equivalent of Transform, with some additional functionality like anchoring.
From the Unity docs:
The Rect Transform component is the 2D layout counterpart of the Transform component. Where Transform represents a single point, Rect Transform represent a rectangle that a UI
element can be placed inside. If the parent of a Rect Transform is also a Rect Transform, the child Rect Transform can also specify how it should be positioned and sized relative to the parent rectangle.
The docs don't actually clearly state anywhere that a transform gets replaced by RectTransform automatically though...
Furthermore Canvas depends on RectTransform, and can thus not be used without having a RectTransform. You can see ths when you try to delete the rect transform from a canvas. It will pop up saying "Can't remove RectTransform because Canvas depends on it".
Any other UI component you add to a GameObject will also automatically add the Recttransform component (I.E image, text etc.). this has the same reason as Canvas, that they depend on RectTRansform.
You will also notice that any GameObject you make that is a child of a canvas will also have a RectTransform by default, so that it can anchor itself relative to the parents (canvas in this example) rect transform. You can delete the rectTransform from these Objects as long as none of its components depend on RectTransform. Though i don't see why this would be desired, as any child of a canvas should be some form of UI like an image or text. And should thus require the RectTransform.
Related
I have a GameObject with a RectTransform that I would like to remove via script.
In other words, I want to replace the RectTransform with a regular Transform in the inspector using a script.
In the inspector, you can simply click the RectTransform dropdown and select Remove Component from there and the RectTransform is replaced with Transform. Of course this only works if there are no Components that rely on the RectTransform directly.
If I try this approach with a script like: Destroy(GetComponent<RectTransform>()) I get an error stating:
Can't destroy RectTransform component of
'MyGameObject'. If you want to destroy the game
object, please call 'Destroy' on the game object instead. Destroying
the RectTransform component is not allowed.
Of course, this is somewhat expected, since you can't remove a transform from a gameObject. In the case where I am trying to get back the old Transform component however, this behavior is undesirable.
So my question is: is there a way to replace the current RectTransform with a simple Transform component via script, and how is this done?
You can't delete a conversion.Alternatively, create an empty object and move the entire hierarchy located on that object there. You can simply change the parent of the first child and align the local position, or implement a more complex system, depending on what you need it for.
I want to move an Text object, and the part of code is as follows.
GameObject.transform.position = new Vector3(-210, -200, 0);
When I execute and check the posX of GameObject in Unity, its value becomes -1170(in 1920x1080), -1653.566(16:9). But posY can work properly. I've set the reference convolution to 1920x1080, and I think it may it have something to do with the resolution settings. Is there any thing wrong? Thanks.
If you are talking about unity ui text you should do it like this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UITestSO : MonoBehaviour
{
public Text textObject;
void Start ()
{
//Position relative to parent transform
textObject.rectTransform.localPosition = new Vector3 (-210, -200, 0);
//Position in world space
textObject.rectTransform.position = new Vector3 (-210, -200, 0);
}
}
All the UI objects(text, image etc.) are parented by canvas object in unity. Canvas behaves differently based on it's screen space setting as follows -
Screen Space - Overlay : If the screen is resized or changes resolution, the Canvas will automatically change size to match this.
Screen Space - Camera : If the screen is resized, changes resolution, or the camera frustum changes, the Canvas will automatically change size to match as well.
Screen Space - World : The Canvas will behave as any other object in the scene. The size of the Canvas can be set manually using its Rect Transform.
The default setting is Screen Space - Overlay Which is the reason you are getting different position values for your text object on different resolutions.
The unity UI elements uses RectTransform. From unity docs
The Rect Transform component is the 2D layout counterpart of the
Transform component. Where Transform represents a single point, Rect
Transform represent a rectangle that a UI element can be placed
inside. If the parent of a Rect Transform is also a Rect Transform,
the child Rect Transform can also specify how it should be positioned
and sized relative to the parent rectangle.
So, to set position of UI elements use RectTransform's anchoredPosition variable, which sets the position of the pivot of this RectTransform relative to the anchor reference point.
textObject.rectTransform.anchoredPosition = new Vector3 (-10, -10, 0);
Reference to rect transform script API.
In Unity, the transform values you see in the inspector are relative to the gameobject's parent. However, when you try to set value for a gameobject's position (by assigning transform.position = ...), you are dealing with position relative to world's center (i.e Vector(0,0,0)). This holds true for whether you are dealing with 3d or 2d.
So, if the parent object is at Vector(0,0,0), world and local positions would be same. There isn't anything wrong with the resolution. You need to set values relative to your parent.
This is how you set values for objects.
anObject.transform.localPosition = new Vector3 (X, Y, Z);
Although there is nothing stopping you from using the same for 2d workflow, RectTransforms are used over simple Transform.
I'm instantiating a GO that has a panel component (RectTransform) as child of a canvas existing in the scene:
_heroSelectUI = (GameObject)Instantiate (_heroSelectUIPrefab, GameObject.Find ("Canvas").GetComponent<Transform>());
When it's created it gets the following values:
"Left", "Top", "Right" and "Bottom" get some unwanted values (probably due to the existing canvas which seems to have identical values).
The panels prefabs values are 0, how to set them back to 0 after instantiation? I can't find the proper variables for the RectTransform.
According to the documentation
For a stretching Rect Transform, it can be simpler to set the position using the offsetMin and offsetMax properties. The offsetMin property specifies the corner of the lower left corner of the rect relative to the lower left anchor. The offsetMax property specifies the corner of the upper right corner of the rect relative to the upper right anchor.
Try to do as follow :
RectTransform rt = _heroSelectUI.GetComponent<RectTransform>();
rt.offsetMin = rt.offsetMax = Vector2.zero ;
Else, according to the documentation too, you can try to do it when setting the parent :
Prefabs of UI elements are instantiated as normal using the Instantiate method. When setting the parent of the instantiated UI element, it’s recommended to do it using the Transform.SetParent method with the worldPositionStays parameter set to false.
_heroSelectUI = (GameObject)Instantiate (_heroSelectUIPrefab, GameObject.Find ("Canvas").GetComponent<RectTransform>(), false);
OR :
_heroSelectUI = (GameObject)Instantiate (_heroSelectUIPrefab );
_heroSelectUI.GetComponent<Transform>().SetParent( GameObject.Find ("Canvas").GetComponent<RectTransform>(), false ) ;
I've tried using this
Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
It successfully created objects, as seen in my hierarchy. But I cannot see the text on the screen, even though there is a text assigned to it. I can only see an empty game object on the screen.
These screenshots show the game on play, and the selected object is the object instantiated through the script.
When I drag the prefab, it does not show anything on the scene. This happens to all my prefabs. The following are its components:
In new Unity3D UI system, every UI (Text, Button, Panel etc.) component that will be renderer on screen must have a parent Canvas component.
You actually do use such approach in your project, where you have Toolbar, List etc. that have parent called Canvas and which I suppose has Canvas component attached.
What you need to do is to move instantiated gameObject to be child of other gameObject that holds Canvas component.
As there can be multiple components of Canvas type, I would suggest to add possibility to assign root for instantiated objects inside your Script.
Script:
//Drag and drop this from inspector; make sure that dragged gameObject
//has Canvas component in it or above it (in parent)
public Transform EntriesRoot;
void Start()
{
var entry = Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
//Put parent to our EntriesRoot
//EntriesRoot will be our new parent for entry in hierarchy
entry.transform.SetParent(EntriesRoot)
}
they need to be a child of a Canvas, that displays them.
// find canvas
GameObject canvas = GameObject.Find("Canvas");
// clone your prefab
GameObject text = Instantiate(entry, new Vector3(x, y, 0), Quaternion.identity);
// set canvas as parent to the text
text.transform.SetParent(canvas.transform);
For each instance, you might have to manually enable the guiTexture.
In my game, if it is the first time the player has ever played the game then I have an image that is displayed. I instantiate it in the canvas like so:
if (PlayerPrefs.GetInt("First Time", 1) == 1)
{
introEnabled = true;
//pause all activity
pause.pauseOrResume();
intro = Instantiate (Resources.Load ("intro"), transform.position, Quaternion.identity) as GameObject;
Canvas canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
intro.transform.SetParent(canvas.transform, false);
//robot = Instantiate (Resources.Load ("robot"), transform.position, Quaternion.identity) as GameObject;
PlayerPrefs.SetInt("First Time", 0);
PlayerPrefs.Save();
}
I can see in the inspector when the game is running that when the object is created, it does show up in the canvas. I just have no idea why it won't show up on top of all of the other objects in the canvas.
The canvas rendering mode is set to "Screen space - Overlay" and it is set to 0 in the sort order. The game object being instantiated also has a sort order of 0 and it is in the default layer.
Nothing I have tried has worked. The z values make no difference and even putting the canvas and the instantiated object in the Default layer and setting the canvas to a sort order of 2 and the instantiated object to a sort order of 1 (so it is rendered first) does not make a difference.
What you want is to use transform.SetAsLastSibling() . The CanvasRenderer renders the GameObjects in order according to their sibling index's (position in the hierarchy), from top to bottom.
However, after examining your code further I noticed something and I should say that if you are trying to instantiate the intro screen, I would highly recommend to instantiate it with it's own Canvas, instead of parenting it to the existing one. Something that significant should have it's own dedicated Canvas.
Update: The problem here is that you are instantiating GameObjects with a transform and Sprite renderer. Canvas UI gets rendered last, over all mesh layers, so if you want your newly instantiated GameObjects to participate, they will need to have RectTransform and Image components instead.
Instead of Default layer change its layer to UI.
You code seems fine, it might be problem related to the gameobject where this script is attached (because you are passing transform.position in Instantiate). it might be positioning the Instantiated game object off the canvas. Try like this once it might work.
intro = Instantiate (Resources.Load ("intro")) as GameObject;
and after setting its parent(very important), set it's position like this
intro.transform.localPosition = new vector3(0,0,0);