I'm instantiating a prefab panel in unity and i'm settings it's parent to another panel like this :
GameObject notificationPanel = (GameObject) Resources.Load("NotificationWindow");
Text notificationText = notificationPanel.GetComponentInChildren<Text>();
if (notificationType == NotificationType.Warning)
{
notificationText.color = Color.red;
}
notificationText.text = text;
GameObject newNotificationWindow =
(GameObject) Instantiate(notificationPanel, new Vector3(0, 0, 0), Quaternion.identity);
newNotificationWindow.transform.SetParent(Settings.NotificationHolder.transform);
However when instantiated it's with an insane size, the parent panel has a layout group with a fixed size of the cell's inside of it why isn't this affecting it ? The new panel is around 10 times bigger than my screen. In the hierarchy view the new panel appears as a child correctly under it's parent. Also the 'z' position is around - 3900 why ?
So After reading the Unity Documentation: Instantiating the UI element all you have to do is to call:
newNotificationWindow.transform.SetParent(Settings.NotificationHolder.transform, false);
The "false"represents worldPositionStays parameter and this scales the UI.
Let me know if this works for you.
Related
I've created a text mesh in Unity like this:
var theText = new GameObject();
var textMesh = theText.AddComponent<TextMesh>();
var meshRenderer = theText.AddComponent<MeshRenderer>();
textMesh.text = name;
textMesh.transform.position = new Vector3(0, 5, 0);
theText.transform.position = new Vector3(0, 5, 0);
The same kind of transformation works on other objects such as a quad. I do not really know which object I should transform, so I tried both textMesh and theText, also separately.
When I click "Play" in Unity and select the created object in the scene, then the contour of the text is highlighted in orange at the correct position. However, the visible white text is still at (0, 0, 0).
This is not only in scripting; when I create a "3D Object/3D Text" via the Unity UI and drag it around with the mouse, it's the same issue.
Why are you creating the text mesh in code? Just go to GameObjects -> UI -> Text or Text Mesh Pro and create it and place it in your scene. If you need to move it just reference
gameObject.transform.position
in a script attached to it.
edit: try removing
textMesh.transform.position = new Vector3(0, 5, 0);
second edit: sorry wasn't paying attention, you just need to change move theText (the game object)
If you assign a color to your text you will be able to see it. Try this code:
var theText = new GameObject();
var textMesh = theText.AddComponent<TextMesh>();
var meshRenderer = theText.AddComponent<MeshRenderer>();
textMesh.text = name;
textMesh.color = Color.red; //THIS IS THE NEW LINE
textMesh.transform.position = new Vector3(0, 5, 0);
theText.transform.position = new Vector3(0, 5, 0);
Hope I've helped you.
I changed TextMesh to TextMeshPro (which requires the import using TMPro;). TextMeshPro is experimental/unstable at the time of writing, and also the positioning seems to be inconsistent with the positioning of the basic 3D objects, but it's an acceptable solution for me at the moment.
If someone finds a real solution using TextMesh, I'm happy to select their answer as correct!
I have an enemy that has children in it; the enemy also has a death animation. Within the death animation (using the animator), I have scaled the enemy to an appropriate size. However, the children within the enemy is also being scaled down even though I have a animation on the child where I have sized it, I also added anchor positions on this child. Is there a way I can scale down the enemy but also keep the size of the child, p.s. the child is a UI text object. Thank you!
The easiest way to solve your problem that I see is to introduce another GameObject higher in the hierarchy.
This GameObject would be the parent of your enemy object and your Text object which currently is a child of the enemy.
This way you can scale the enemy independently of the Text.
Maybe (hopefully) there are better solutions but you could use a component on the child objects that always keeps the original scale inverting relative changes in the parents scale
public class FreezeScale : MonoBehaviour
{
private Vector3 originalScale;
private Vector3 parentOriginalScale;
private void Awake()
{
// afaik RectTransform inherits from Transform
// so this should also work for UI objects.
originalScale = transform.localScale;
parentOriginalScale = transform.parent.localScale;
}
private void LateUpdate()
{
var currentParentScale = Transform.parent.localScale;
// Get the relative difference to the original scale
var diffX = currentParentScale.x / parentOriginalScale.x;
var diffY = currentParentScale.y / parentOriginalScale.y;
var diffZ = currentParentScale.z / parentOriginalScale.z;
// This inverts the scale differences
var diffVector = new Vector3 (1/diffX, 1/diffY, 1/diffZ);
// Apply the inverted differences to the original scale
transform.localScale = originalScale * diffVector;
}
}
Not tested since hacked in on my mobile phone but I hope you get the idea ;)
set the child's scale to world space not local space.
local space is the default, but it will go off of the scale of the parent so when the enemy shrinks so will the text.
alternatively you could set both objects to be children of an empty object, then just scale your enemy down and the text should stay the same size since its using the scale of the empty parent, which isn't changing size either.
see here:
public static Vector3 GetWorldScale(Transform transform)
{
Vector3 worldScale = transform.localScale;
Transform parent = transform.parent;
while (parent != null)
{
worldScale = Vector3.Scale(worldScale,parent.localScale);
parent = parent.parent;
}
return worldScale;
}
just a work around though, your meant to use this:
yourtransform.LocalScale=Transform.localToWorldMatrix
but it gives me issues... the above method works well though.
transform.scale=GetWorldScale(transform);
edit: lets be clear, the easiest thing to do would be to unpraent the objext before shrinking the parent. this will separate the scales.
I have a random world with some trees that get randomly instantiated.
I use the following code to instantiate them:
GameObject go = Instantiate(treePrefab);
go.name = "Tree";
go.tag = "Wood";
go.layer = 9;
go.transform.position = new Vector3(y + UnityEngine.Random.Range(-0.5f, 0.5f), heightPos, x + UnityEngine.Random.Range(-0.5f, 0.5f));
go.transform.Rotate(0, UnityEngine.Random.Range(0, 360), 0);
x and y are part of a for loop that goes through all positions (like a grid) of my world.
heightPos is the current height of the terrain at the specific point (x/y).
My problem is that the prefab ob the trees has the position 0, 0, 0.
Every tree that get's instantiated gets set to 0, 0, 0 too.
I use the exact same code to instantiate rocks, cactus, feathers, car's and many other things, and it works perfect.
but it always fails at the trees.
I've looked through the code and there is no difference to the other objects, except the prefab (of course).
So i think it has to do something with the settings of the prefab.
But my prefab got no animator, it is not static or something.
This is what my tree-Prefab looks like in the inspector:
and this is what it looks like in scene view:
You can create another gameobject and make this instance as a child of that gameobject so even if the instance is always at (0, 0, 0) you can always change the position of the parent object.
I have been looking on the code for ARCore Unity for a while and I want to do one simple task that is, to have a toggle button so user can place an object in the scene while knowing where to place it while the tracked planes are visible and once the user places the object, he is given the option of just visually disabling the tracked planes so it looks more realistic. I was able to do this in Android Studio by doing something like this in the main HelloArActivity.java:
if (planeToggle) {
mPlaneRenderer.drawPlanes(mSession.getAllPlanes(), frame.getPose(), projmtx);
}
this was really simple. I made a bool named planeToggle and just placed the mPlaneRenderer.drawPlanes function in an if condition. When the bool is true it displays the planes and when its false, it does not...
However, with Unity I am confused. I did something like this in the HelloARController.cs :
I made a button to togglePlanes.
Set an event listener to it to toggle a boolean variable and did something like this :
for (int i = 0; i < m_newPlanes.Count; i++)
{
// Instantiate a plane visualization prefab and set it to track the new plane. The transform is set to
// the origin with an identity rotation since the mesh for our prefab is updated in Unity World
// coordinates.
GameObject planeObject = Instantiate(m_trackedPlanePrefab, Vector3.zero, Quaternion.identity,
transform);
planeObject.GetComponent<TrackedPlaneVisualizer>().SetTrackedPlane(m_newPlanes[i]);
m_planeColors[0].a = 0;
// Apply a random color and grid rotation.
planeObject.GetComponent<Renderer>().material.SetColor("_GridColor", m_planeColors[0]);
planeObject.GetComponent<Renderer>().material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f));
if (togglePlanes == false){ // my code
planeObject.SetActive(false); // my code
} //
}
Nothing happens when I press the toggle button.
The other option I had was to make changes in the TrackedPlaneVisualizer.cs where I did something like this :
for (int i = 0; i < planePolygonCount; ++i)
{
Vector3 v = m_meshVertices[i];
// Vector from plane center to current point
Vector3 d = v - planeCenter;
float scale = 1.0f - Mathf.Min((FEATHER_LENGTH / d.magnitude), FEATHER_SCALE);
m_meshVertices.Add(scale * d + planeCenter);
if (togglePlanesbool == true) // my code
{
m_meshColors.Add(new Color(0.0f, 0.0f, 0.0f, 1.0f)); // my code
}
else
{
m_meshColors.Add(new Color(0.0f, 0.0f, 0.0f, 0.0f)); // my code
}
}
This did work. But I am experiencing delays in toggling and sometimes if two different planes have been rendered they start toggling between themselves(if one is enabled, other gets disabled). So I guess this is also not the option to go for....Anyone who can help?
Note that I am a beginner in Unity.
The sample isn't really designed to hide and show the planes, so you have to add a couple things.
First, there is no collection of the GameObjects that represent the ARCore planes. The easiest way to do this is to add a tag to the game objects:
In the Unity editor, find the TrackedPlaneVisualizer prefab and select it. Then in the property inspector, drop down the Tag dropdown and add a tag named plane.
Next, in the Toggle handler method, you need to find all the game objects with the "plane" tag. Then get both the Renderer and TrackedPlaneVisualizer components and enable or disable them based on the toggle. You need to do both components; the Renderer draws the plane, and the TrackedPlaneVisualizer re-enables the Renderer (ideally it would honor the Renderer's state).
public void OnTogglePlanes(bool flag) {
showPlanes = flag;
foreach (GameObject plane in GameObject.FindGameObjectsWithTag ("plane")) {
Renderer r = plane.GetComponent<Renderer> ();
TrackedPlaneVisualizer t = plane.GetComponent<TrackedPlaneVisualizer>();
r.enabled = flag;
t.enabled = flag;
}
}
You can also do a similar thing where the GameObject is instantiated, so new planes honor the toggle.
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));