How to create new parent child gamobjects at runtime? - c#

For a button click two new gameObjects are created and the second one is setting as a child of first one and first one is child of attached object. But it is not working / showing on hierarchy but the created object is not appearing in game window.
Here is the code:
public void CreateTextButtonClick(string text)
{
Debug.Log("Hey starting of this..");
//Create Canvas Text and make it child of the Canvas
GameObject txtObj = new GameObject("myText");
txtObj.transform.SetParent(this.transform, false);
GameObject pan = new GameObject("text");
pan.transform.SetParent(txtObj.transform);
//Attach Text,RectTransform, an put Font to it
Text txt = pan.AddComponent<Text>();
txt.text = text;
Font arialFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
txt.font = arialFont;
txt.lineSpacing = 1;
txt.color = Color.blue;
//image
//GameObject back = new GameObject("image");
//back.transform.SetParent(txtObj.transform);
//Image i = back.AddComponent<Image>();
Debug.Log("Hey its done..");
}
What can be a solution to achieve this multi level object making?

You used SetParent properly in the first Object you want to be child of your Canvas by passing false to it which causes it to keep its local orientation:
GameObject txtObj = new GameObject("myText");
txtObj.transform.SetParent(this.transform, false);
But you did not do this for the "text" Object that will be child of the object above:
GameObject pan = new GameObject("text");
pan.transform.SetParent(txtObj.transform);
You can fix that by also passing false to it so that the UI component to keep its local orientation. Unrelated but I also think you should add a RectTransform the parent object too. Add RectTransform to anything that will be under the Canvas.
Your new code:
public void CreateTextButtonClick(string text)
{
Debug.Log("Hey starting of this..");
//Create Canvas Text and make it child of the Canvas
GameObject txtObj = new GameObject("myText");
txtObj.AddComponent<RectTransform>();
txtObj.transform.SetParent(this.transform, false);
GameObject pan = new GameObject("text");
pan.transform.SetParent(txtObj.transform, false);
//Attach Text,RectTransform, an put Font to it
Text txt = pan.AddComponent<Text>();
txt.text = text;
Font arialFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
txt.font = arialFont;
txt.lineSpacing = 1;
txt.color = Color.blue;
}
In your commented code, it looks like you plan to add another child object with Image component too and I can already see that mistake there. Do not forget to do this too. You must otherwise, you will have issues. This applies to everything you plan to place under the Canvas.

Related

button.transform.parent = shopPanel; and button.transform.SetParent(shopPanel); not working

I'm attempting to create a new button game object. When I click the button to create the new game objects, it does not assign the game objects to the parent I'm telling it to.
public void DisplayUpgrades()
{
// Get the RectTransform component of the shop panel
RectTransform shopPanelRectTransform = shopPanel.GetComponent<RectTransform>();
// Set the initial position of the first button to 0
float yPos = 0;
foreach (var upgrade in upgrades)
{
// Create a new button game object
GameObject button = new GameObject();
button.name = "UpgradeButton";
// Set the parent of the button to the shop panel
button.transform.parent = shopPanel;
// Set the size of the button to 10 units wide and 10 units tall
button.transform.localScale = new Vector3(10, 10, 1);
// Add a RectTransform component to the button
RectTransform rectTransform = button.AddComponent<RectTransform>();
// Set the position of the button using the RectTransform component
rectTransform.localPosition = new Vector3(0, yPos, 0);
rectTransform.sizeDelta = new Vector2(150, 20);
// Add a Button component to the button
Button btn = button.AddComponent<Button>();
btn.transform.SetParent(shopPanel);
// Add a TextMeshProUGUI component to the button
TextMeshProUGUI text = button.AddComponent<TextMeshProUGUI>();
text.transform.SetParent(shopPanel);
// Set the font size of the text to 20 pixels
text.fontSize = 8;
text.alignment = TextAlignmentOptions.Center;
// Set the text of the button to the name and cost of the upgrade
text.text = $"{upgrade.Key}: cost: {upgrade.Value.cost}";
// Add a listener to the button to handle when it is clicked
btn.onClick.AddListener(() => PurchaseUpgrade(upgrade.Key));
// Increment the y position by 20 pixels for the next button
yPos += 90;
}
}
To give some more info, I have 2 GUI elements, a canvas named 'Canvas' (parent of shopPanel), and 'shopPanel'. When I create new objects, they are being created as children of 'Canvas' rather than 'shopPanel'. 'shopPanel' is a Rect Transform. 'Canvas', also is a Rect Transform. I am needing 'button' to be a child of 'shopPanel' because when I want to add additional GUI elements, I don't want the addtl GUI elements to be destroyed when I attempt to destroy the children of shopPanel.
I have attempted button.transform.parent = shopPanel;, button.transform.SetParent(shopPanel). I have tried to see if 'button' is a child of 'shopPanel', and if it isn't, assign it as the Parent. I have tried creating different canvas's and different shop panels. I've tried restarting the program and my computer. Nothing has worked this far.

UI text is not rendered but appearing in hierarchy — what is missing?

trying to show text dynamically created to the canvas but its not rendering.
After creating canvas an empty gameObject attached as child and the following script is attached to that. After running the object appears in hierarchy but not rendered.maybe I'm missing something:
GameObject o;
void Start() {
GameObject test = new GameObject("myTextGO");
test.transform.SetParent(this.transform);
// test.transform.SetParent(o.transform);
Text myText = test.AddComponent<Text>();
myText.text = "Hello there!";
}
Also tried few other combination but not text is not rendering. Need to know solution.
Three things required to do when creating UI text dynamically and manually:
Font
Proper Parenting
RectTransform (Now, automatically attached by Unity when UI component
is attached to a GameObject)
I assume that you are using the latest Unity version so you just need to do the first two:
Supply font for the Text component to use as mentioned this answer. Also, when using transform.SetParent, you have to supply false to it. This causes the UI component to keep its local orientation.
void CreateText(GameObject canvas, string text)
{
//Create Canvas Text and make it child of the Canvas
GameObject txtObj = new GameObject("myTextGO");
txtObj.transform.SetParent(canvas.transform, false);
//Attach Text,RectTransform, an put Font to it
Text txt = txtObj.AddComponent<Text>();
txt.text = text;
Font arialFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
txt.font = arialFont;
txt.lineSpacing = 1;
txt.color = new Color(50 / 255, 50 / 255, 50 / 255, 255 / 255);
}
Usage:
public GameObject canvas;
void Start()
{
CreateText(canvas, "Hello there!");
}
That's how to create a text component manually but that should no longer be used. Let Unity do this automatically. The DefaultControls should be used to create UI Objects. It reduces the chances that the creation code will fail or that you'll run into similar issues in your question. Create the Text resources with DefaultControls.Resources then the Text itself with DefaultControls.CreateText.
void CreateText(GameObject canvas, string text)
{
DefaultControls.Resources uiResources = new DefaultControls.Resources();
GameObject uiText = DefaultControls.CreateText(uiResources);
uiText.transform.SetParent(canvas.transform, false);
uiText.GetComponent<Text>().text = text;
//Change the Text position?
//uiText.GetComponent<RectTransform>().sizeDelta = new Vector2(100f, 100f);
}
There is no font attached to the Text-object.
Try adding this line
myText.font = Resources.GetBuiltinResource<Font>("Arial.ttf");

controlling a spawned picturebox

I am trying to make a little game coded in c#, the game involves moving enemies.
These enemies are spawned in using the following code, this code is used multiple times to spawn multiple enemies.
private void EventHandler(Action<object, EventArgs> spawnBox)
{
Random randomPlek = new Random();
int xPlek;
xPlek = randomPlek.Next(1000, 1100);
int yPlek;
yPlek = (randomPlek.Next(0, 8)) * 100;
var picture = new PictureBox
{
Name = "pictureBoxLM",
Size = new Size(150, 100),
SizeMode = PictureBoxSizeMode.StretchImage,
BackColor = Color.Transparent,
Location = new Point(xPlek, yPlek),
Image = Leeuwenmier,
};
this.Controls.Add(picture);
}
The problem is that when trying to make them move or collide, Visual Studio can't find the name and gives an error. This is the code i used for collision:
if(PbMier.Bounds.IntersectsWith(pictureBoxLM.Bounds))
{
// some actions
}
How can I call the spawned picturebox in the code without getting an error?
WinForms controls have names, but that doesn't mean you can access them using that name as a C# identifier.
Your PictureBox only has a named reference within EventHandler(), namely picture, but once control leaves that method that reference goes out of scope.
You need to find the controls again, or find another way to reference the generated controls.
So either:
var allPictureBoxes = this.Controls.Find("PictureBoxLM");
foreach (var pictureBox in allPictureBoxes)
{
// ...
}
Or put this on your form:
List<PictureBox> pictureBoxList = new List<PictureBox>();
And then in the EventHandler();
this.Controls.Add(picture);
pictureBoxList.Add(picture);
After which you can use this for your collision detection:
foreach (var pictureBox in pictureBoxList)
{
// ...
}

In Unity, how to access children component of the prefab using script?

Prefab hierarchy:
Button
1 Text
2 Image
I wish to access Image child component of the prefab.
I tried the following code:
GameObject addTypeButton = (GameObject)Instantiate(prefabButton);
addTypeButton.transform.SetParent(ParentPanel, false);
//set text
addTypeButton.GetComponentInChildren<Text>().text ="Some string";
//get image
WWW www = new WWW("someImagelink");
yield return www;
//set image
addTypeButton.GetComponentInChildren<Image>().sprite = Sprite.Create(www.texture, new Rect(0, 0, www.texture.width,www.texture.height), new Vector2(0, 0));
However, the above code is accessing Image script of Button (inbuilt).
Not the Image UI component.
How do I access UI Image (child) component?
Please help.
Thanks!
The Cause
GetComponentInChildren will also return component on the gameObject itself.
public Component GetComponentInChildren(Type t);
Returns the component of Type type in the GameObject or any of its children using depth first search.
Solutions
If the index of child GameObject 1 Text and 2 Image is fixed. You can get them by Transform.GetChild(index).
var buttonTransform = addTypeButton.transform;
var text = buttonTransform.GetChild(0);
var image = buttonTransform.GetChild(1);
If the order is not fixed, use Transform.Find(childName).
var buttonTransform = addTypeButton.transform;
var text = buttonTransform.Find("1 Text");
var image = buttonTransform.Find("2 Image");
The safest solution:
Drag your prefab to scene and attach a script to your Button GameObject:
using UnityEngine;
using UnityEngine.UI;
public class MyButton : MonoBehaviour
{
public Text text;
public Image image;
}
Then drag 1 Text and 2 Image to text and image field in the inspector of the Button.
Remember to press apply button and Ctrl+S to save that into your prefab.
In this way you can access the text and image like:
var mybutton = addTypeButton.GetComponent<MyButton>();
mybutton.text.text = "Some string";
mybutton.image.sprite = Sprite.Create(...);
Before accessing the child object, please make sure that that child object is enabled in prefab before enabling or disabling it after getting instantiated.
Like in my case, I had a UI Text game object with an image child object. I disabled it in the prefab with the hope to enable it by reference in the script after instantiating it. It only worked if I kept the image(child) component enabled in the prefab.
Try changing
addTypeButton.GetComponentInChildren<Image>().sprite = Sprite.Create(www.texture, new Rect(0, 0, www.texture.width,www.texture.height), new Vector2(0, 0));
To
addTypeButton.GetComponent<Image>().sprite = Sprite.Create(www.texture, new Rect(0, 0, www.texture.width,www.texture.height), new Vector2(0, 0));

Instantiating World Canvases

I am trying to instantiate many world canvases and it gives me this error:
UnityEngine.UI.Text.Text()' is inaccessible due to its protection
level, UnityEngine.UI.Image.Image()' is inaccessible due to its
protection level
I have created an prefab which contains a canvas set to world space, and I can't understand the right approach to instantiate them. here is a copy of the script:
public void PositionWorldCanvases ()
{
for (int i = 0; i < vertices.Length; i++) {
Canvas can = new Canvas();
Text text = new Text();
Image image = new Image();
Instantiate (canvasManager, vertices[i], Quaternion.identity);
can = canvasManager.GetComponentInChildren<Canvas> ();
image = can.GetComponent<Image> ();
text = image.GetComponent<Text> ();
text.text = "Hello World";
}
}
Its not a problem with instantiating, its a problem with construction.
Text and Image have private constructors, so they cannot be created out of scope using the new keyword, you have to attach them manually to an empty GameObject with a RectTransform and CanvasRenderer component. then you instantiate that object.

Categories