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);
Related
I am trying to spawn obstacles on the road. To do so, I generate a road by spawning its parts, and each part itself spawns several obstacles in bounds of themselves. But some prefabs after being instantiated got strange "stretching" effects. I don't know how to explain it, so I recorded a small video link. Also, if I spawn that same object by "drag n drop" to the scene, this bug never appears.
This how I spawn obstacles:
Vector3 size = GetComponent<Renderer>().bounds.size;
Vector3 pos = new Vector3(Random.Range(-0.3f*size.x,0.3f*size.x), 30, Random.Range(-0.3f*size.z,0.3f*size.z));
Debug.Log(pos + transform.position +"");
GameObject newBottle = Instantiate(minus_prefabs[Random.Range(0, minus_prefabs.Length)], new Vector3(transform.position.x+pos.x,transform.position.y + pos.y,transform.position.z+pos.z), Quaternion.Euler(0, 0, 0));
newBottle.transform.SetParent(transform);
This happens because the parent GameObject of the model has diffrent sizes on X, Y and Z. This results in some weird stretching. Try going in your prefab and set the scale of your main GameObject to X:1 Y:1 Z:1 for example.
Also see: https://www.unity3dtips.com/how-to-fix-objects-stretching-when-rotated/#:~:text=Cause%20of%20the%20object%20stretching,0.01%2C%200.002%2C%200.004%E2%80%9D.
This also happens to me all the Time. Thankfully its easy to fix!
EDIT: When you instantiate the prefab, also make sure it has the same sizes on every axis.
As a general rule, whenever possible, don't use any Scale other than 1,1,1 unless you need to and it should be on a leaf node of the hierarchy or prefab not a parent node. It will make things go much smoother. If you need to change the size of a mesh (because the noob modeler didn't know how to follow the life-sized scaling metrics in their modeling program, or you just want it smaller or larger), you can do that in the Import settings on the FBX.
Ran into a U.I problem that I am struggling to solve (UI is always an issue for me). Gist of the project is that I have an array of spawn points (Positions[i]), an array composed of enemy prefabs(Enemies[j]) and just a UI panel prefab with a text component (EnemyHUD). When I pass string names through a certain function, as long as there is a prefab with the same name and position available to it, it will load in the enemy. Now, for every enemy prefab loaded in, I would like a "EnemyHUD" prefab to instantiate at at the enemy positions and with text displaying the name of the enemy.
GameObject HUD = Instantiate(EnemyHUB, Positions[i].position, Positions[i].rotation);
This line spawns the EnemyHUD prefab at the right location but its Instantiates them outside of the canvas so they show up as red x's. So I added this:
HUD.transform.SetParent(GameObject.Find("Canvas").transform, false);
This fixes the issue of Instantiating outside of the canvas but also (irritatingly)resets the Instantiate position and embarrassingly, I'm not sure how to set it back while making sure it stays a child of the Canvas. Have not event touched the name change part yet.
I have been working on this this since last night and while I got a lot of different results experimenting, none have been the one that I want. Very much still a novice, so I am sure it is looking me in the face so please help me find it.
First of all I would strongly recommend to avoid Find whenever possible! Rather already reference the according Canvas and store its reference. Especially the i lets assume you are doing this in a loop so using Find repeatedly is extremely inefficient!
// Drag you Canvas object into this field via the Inspector in Unity
[SerializeField] private Canvas _parentCanvas;
private void Awake()
{
// use this only as fallback an only ONCE
if(!_parentCanvas) _parentCanvas = GameObject.Find("Canvas");
if(!_parentCanvas) Debug.LogError("Could not get Canvas!", this);
}
Well and then the second parameter of Transform.SetParent is called
worldPositionStaysIf true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.
And
The default value of worldPositionStays argument is true.
Simply either leave it out like
HUD.transform.SetParent(_parentCanvas);
// this equals
//HUD.transform.SetParent(_parentCanvas, true);
or you could even do it in one single go already in Object.Instantiate which takes an additional parameter
parent Parent that will be assigned to the new object.
// This directly instantiates the new hud as child of _parentCanvas
// while still taking the position and rotation in absolute worldspace
GameObject HUD = Instantiate(EnemyHUB, Positions[i].position, Positions[i].rotation, _parentCanvas);
I have a custom UI element in the Mainmenu scene that works fine, but when i make a prefab out of it, all the text and images become invisible, and the rect transform goes blank
The orginal prefab
the instatiated invisible prefab
You should instantiate it as a child object of Canvas.
Instantiate(prefab, thatCanvas.transform);
I read many questions about this, but I still can't find what my problem is...
I'm trying to instantiate a prefab at the canvas. It is compose of a button and a sprite. The button looks ok, but the sprite is not visible at the Game (but is visible at the Scene).
I'm doing something wrong, but I can't see what...
[SerializeField] GameObject finishedLevel;
private void Start()
{
finishedLevel = Instantiate(finishedLevel, transform.position, transform.rotation);
finishedLevel.transform.SetParent(GameObject.FindGameObjectWithTag("Canvas").transform, false);
}
SpriteRenderer is not made to be used with the Canvas. You are confusing and misusing the two.
SpriteRenderer is used for displaying 2D Objects like a 2D animated character or a 2D environment. You can attach Rigidbody2D and Colliders to SpriteRenderer.
Canvas is used for UI display only. It is used for displaying things such as UI texts, buttons, sliders, scrollbars and images. You shouldn't attach Rigidbody2D and Colliders to it or its child objects.
With the explanation above, you should be able to determine which one to use. If you just need to display image under a Canvas, use the Image, or RawImage component since they are part of the UI system. This should work but do not make SpriteRenderer a child of a Canvas. If you have to use SpriteRenderer, make it its own object or under another object but it should not be under a Canvas. You may find Unity's UI tutorial useful.
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.