Transform TextMesh in Unity - c#

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!

Related

Detecting overlapping polygon2D colliders in Unity

I'm trying to program an isometric building placement script. Each building has a PolygonCollider2D component on it with a trigger. When placing a new building, I'm trying to check if the PolygonCollider2D of the placed building overlaps with anything else (to check if placement is valid). My code is as follows:
Adjust the points of the new placed building collider based on the mouse position
Vector2[] points = polygonCollider2D.points;
points.SetValue(polygonCollider2D.points[0] + (Vector2)mousePosition, 0);
points.SetValue(polygonCollider2D.points[1] + (Vector2)mousePosition, 1);
points.SetValue(polygonCollider2D.points[2] + (Vector2)mousePosition, 2);
points.SetValue(polygonCollider2D.points[3] + (Vector2)mousePosition, 3);
polygonCollider2D.points = points;
Set up contact filter:
ContactFilter2D contactFilter2D = new ContactFilter2D();
contactFilter2D.useTriggers = true;
contactFilter2D.SetLayerMask(polygonCollider2D.gameObject.layer);
Check for collisions
List<Collider2D> list = new List<Collider2D>();
Debug.Log(polygonCollider2D.OverlapCollider(contactFilter2D, list));
However if there is already a building there, it still does not register an overlap.
What am I missing / doing wrong ?
Thanks so much for the help!
Your code which sets the polygon collider points seems to be the issue here. If that code runs multiple times, it will repeatedly offset the collider further and further away from its original position. You probably don't want to be changing the actual collider; usually you should move object which has the collider. So you would replace those lines with something like this:
gameObject.transform.position = mousePosition;

BulletPhysics - Door object spins uncontrollably when placed on ground

I am trying to simulate a door in BulletPhysics using a HingeConstraint. The following code works as intended, in that the cube pivots on its corner around the Y-axis, effectively swinging open like a door, but as soon as I place the object on the ground it begins flying around uncontrollably.
RigidBody body = physics.LocalCreateRigidBody(mass, Matrix4.CreateTranslation(new Vector3(0, 0.5f, 0)), new BoxShape(1, 1, 1));
body.UserObject = "Door";
Vector3 pivotInA = new Vector3(1, 1, 1);
Vector3 axisInA = new Vector3(0, 1, 0);
var hinge = new HingeConstraint(body, pivotInA, axisInA);
const float targetVelocity = 1.0f;
const float maxMotorImpulse = 1.0f;
hinge.EnableAngularMotor(true, targetVelocity, maxMotorImpulse);
physics.World.AddConstraint(hinge);
Disabling collisions between the door and ground would solve the problem but I am struggling to achieve this also. The documentation says you can set a collision type and mask for a body but only the World.AddRigidBody() constructor appears
to take such parameters and as far as I can tell my door is added to the world as a Hinge and the ground is added automagically when calling LocalCreateRigidBody(), shown below.
CollisionShape groundShape = new BoxShape(10, 1, 10);
CollisionObject ground = LocalCreateRigidBody(0, Matrix4.CreateTranslation(0, -1, 0), groundShape);
ground.UserObject = "Ground";
How can I stop the door spinning out when it sits atop the ground?
You can write your own version of LocalCreateRigidBody that sets up the collision mask. LocalCreateRigidBody is a helper function in the BulletSharp demos and not a built-in function in Bullet.
Here is one way to set up the collision filter:
const CollisionFilterGroups groundGroup = (CollisionFilterGroups)0x40000000;
var groundMask = CollisionFilterGroups.AllFilter ^ CollisionFilterGroups.StaticFilter;
World.AddRigidBody(ground, groundGroup, groundMask);
var doorMask = CollisionFilterGroups.AllFilter ^ groundGroup;
World.AddRigidBody(door, CollisionFilterGroups.DefaultFilter, doorMask);
Another way to solve this is to make the door shorter so it's not close enough to the ground to generate collisions. Then render a larger graphics object in place of the smaller physics object. If you are using the BulletSharp demo framework, then you will have to modify the framework to support this.

Unity Editor Pipeline Scripting: how to Pass Sprite to SpriteRenderer in OnPostprocessSprites() Event?

after importing sprites inside unity , i want to make a Prefab out Of them and assign them a SpriteRenderer and BoxCollider2D component , all automaticly.
every thing is good exept i cant pass the imported Sprite to the SpriteRenderer component any how.
i dont knoow what im missing here. any help will be appritiated.
void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
{
Sprite sp = sprites[0];
TextureImporter importer = (TextureImporter)assetImporter;
importer.textureType = TextureImporterType.Sprite;
GameObject GO = new GameObject();
GO.name = sp.name;
string ResAddress = importer.assetPath.Remove(importer.assetPath.Length - 4, 4).Replace("Assets/Resources/", "");
Debug.Log("Resource Address = " + ResAddress);// Images/Objects/car acceptable for Resource.load
//GO.AddComponent<SpriteRenderer>().sprite = sp;// not works
GO.AddComponent<SpriteRenderer>().sprite = (Sprite)Resources.Load(ResAddress);// not works
GO.AddComponent<BoxCollider2D>();
Object prefab = PrefabUtility.CreateEmptyPrefab(string.Format("Assets/Resources/X_Temp/{0}.prefab", GO.name));
if (prefab != null)PrefabUtility.ReplacePrefab(GO, prefab, ReplacePrefabOptions.ConnectToPrefab);
}
there is no Error or messages , it makes the prefab with BoxCollider And SpriteRendere Components But SpriteRenderer's Sprite Field Has No Sprite, and set to none or Missing.
how can i fix this?
also asked in Unity Community And No luck.
https://answers.unity.com/questions/1434068/how-to-pass-sprite-to-spriterenderer-in-onpostproc.html
https://forum.unity.com/threads/how-to-pass-sprite-to-spriterenderer-in-onpostprocesssprites-event.505638/
====== UPDATE And NOT RECOMMENDED ANSWER ======
void OnPostprocessSprites(Texture2D texture, Sprite[] sprites)
{
TextureImporter importer = (TextureImporter)assetImporter;
if (AssetDatabase.LoadAssetAtPath<Sprite>(importer.assetPath)==null)
{
AssetDatabase.Refresh();
return;
}
foreach (Sprite sp in sprites)
{
importer.textureType = TextureImporterType.Sprite;
GameObject GO = new GameObject();
GO.name = sp.name;
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(importer.assetPath);
GO.AddComponent<SpriteRenderer>().sprite = sprite;
string address = string.Format("Assets/Resources/Prefabs/{0}.prefab", GO.name);
PrefabUtility.CreatePrefab(address, GO);
PrefabUtility.ReconnectToLastPrefab(GO);
}
}
not recommended Because Of the following Crash Error :
A default asset was created for 'Assets/Resources/Images/Objects/car.png' because the asset importer crashed on it last time.You can select the asset and use the 'Assets -> Reimport' menu command to try importing it again, or you can replace the asset and it will auto import again.UnityEditor.AssetDatabase:Refresh()
This is really interesting. I don't think that Resources.Load(ResAddress) is returning null otherwise you should see null if you use Debug.Log on it. I assumed that the texture variable from the OnPostprocessSprites function would work if you convert it to Sprite then assign it to the SpriteRenderer like so:
Sprite tempSprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
GO.AddComponent<SpriteRenderer>().sprite = tempSprite;
That didn't work too despite the fact that tempSprite is not null. This quickly made me remember the AssetDatabase API which is specifically used to access and operate on assets.
You are looking for the AssetDatabase.LoadAssetAtPath function. It will return the proper Sprite asset you can use to change the SpriteRenderer.sprite property.
This should work:
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(assetPath);
GO.AddComponent<SpriteRenderer>().sprite = tempSprite;
It would make sense to call AssetDatabase.Refresh() after all these but it seems to work without calling AssetDatabase.Refresh(). I still think you should call it.

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

Instantiate prefab in Unity

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.

Categories