Jonathan Williams
Jonathan Williams

Reputation: 1

Instantiating a U.I object at the position of another object while keeping the Canvas as the parent

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.

Upvotes: 0

Views: 3062

Answers (1)

derHugo
derHugo

Reputation: 90714

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

worldPositionStays
If 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);

Upvotes: 0

Related Questions