Instantiating World Canvases - c#

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.

Related

How to create new parent child gamobjects at runtime?

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.

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

How to attach a 'TextMesh' property to a Cloned Object on Unity 3D

I'm generating dynamic instances of class object on Unity 3D and are working good, but, when I'm trying to add an extra component TextMesh, I can't access to them to assign text.
The codes are:
Bubble.cs
public class Bubble : MonoBehaviour {
Vector3 offset = Vector3.zero;
Vector3 oldpos = Vector3.zero;
public Team team = Team.Green;
public Color teamColor;
float blastRange = 4.0f;
float moved = 0;
public TextMesh nText = new TextMesh();
void Start () {
score = (Score)FindObjectOfType(typeof(Score));
Game.game.bubbles.Add(this);
nText.text = "123";
}
}
But, when I'm trying to access to the nText property is always null.
Also, I can't link this TextMesh to a component defined in an scene because all the bubbles should have different values.
How, I can fix that?
The error is: UnassignedReferenceException: The variable nText of Bubble has not been assigned.
You probably need to assign the nText variable of the Bubble script in the inspector.
Try
nText = gameObject.AddComponent<TextMesh>()
in your Start method
You should not use the new keyword for Unity components.
public TextMesh nText = new TextMesh();
should be
public TextMesh nText = null;
void Start () {
score = (Score)FindObjectOfType(typeof(Score));
Game.game.bubbles.Add(this);
nText = gameObject.AddComponent("TextMesh") as TextMesh;
nText.text = "123";
}

Categories