How to autosize text on a textmesh - unity3d

How do you auto-size text on a textmesh.
I have dice, with six sides, that I want to put words on. The words will constantly be changing, so I need them to auto size based on the size of the cube, which doesn't change.
The dice are not UI elements and thus sit outside the canvas.
Here is how I am adding the text.
LocationSide1.GetComponent<TextMesh>().text = "1";
LocationSide2.GetComponent<TextMesh>().text = "2";
LocationSide3.GetComponent<TextMesh>().text = "3";
LocationSide4.GetComponent<TextMesh>().text = "4";
LocationSide5.GetComponent<TextMesh>().text = "5";
LocationSide6.GetComponent<TextMesh>().text = "6";
Imagine I want the dice to say "pickle" instead of the 6. The next role it might say "cantaloupe" then "pea". The text will change sizes.
Example how the text sticks over the edge.

The answer you seek can be found on another thread - http://answers.unity3d.com/questions/218222/how-to-calculate-a-textmesh-width-without-renderin.html
public class TextBehaviour : MonoBehaviour
{
public TextMesh textmesh;
void Start ()
{
Bounds bound = BoundOfTextMesh("New Text");
print ("Size X = "+bound.size.x +"Size Y = "+bound.size.y);// Size of X and Y or Vector2
}
Bounds BoundOfTextMesh(string textMeshName)
{
textmesh = GameObject.Find (textMeshName).GetComponent<TextMesh>();
return textmesh.renderer.bounds ;
}
}

TextMesh doesn't have an auto-sizing feature, so to resize the text to fit in its container, you would have to follow Scott Barnes' suggestion of manipulating the Renderer for the desired effect.
If you're looking for alternatives that have the effect you're looking for, you might consider TextMesh Pro. It's a free asset on the Unity store that has Auto-Sizing functionality. The text comes in both 2D UI and 3D Text formats, so it will work both inside and outside of canvases.
TextMesh Pro Auto-Sizing Video

Related

Growing menu with scrollbar

I hate to ask such a generic question but I'm really stuck and super hoping someone can help me along the way. Here is the situation:
I'm making the GUI for a mobile app, portrait mode. I'm using canvas scalers to scale my canvasses with a reference width of 1080. This means I effectively don't know the height of my screen space.
What I want to create is a menu with a variable amount of items. The menu must be anchored to the bottom (with an offset margin) and grow upwards. So far I've been able to manage this using VerticalLayoutGroup and anchoring the rect transform to the bottom.
But my last requirement is that if the content would grow too big, a scrollbar would appear. The definition of the content being too big is: if it would extend the (unknown) screen height ( minus the offset margin of course). I hope the following image illustrates this much clearer:
I have a unity project here: https://ufile.io/v31br
Did you give a try to scrollView? here it is: https://unity3d.com/learn/tutorials/topics/user-interface-ui/scroll-view
You can use your vertical layout inside it and you will probably want to deactivate horizontal scroll and delete the horizontal slider.
Via script you can check its rectTransform height and compare it to your container's size, when reached maxHeight you can start managing your item's sizes
I assume you use the ScrollRect component as it is the right component to use in your case.
You can check the screen height with the Screen.height property.
Once you know the screen height you can compare it with your rect height and toggle the scrollbar with the ScrollRect.vertical property. You may have to change the ScrollRect.verticalScrollbarVisibility to permanent in order to make it work for you.
The answer Dave posted was close, but the problem is that the scrollview doesn't expand. I fixed it eventually by stretching the scrollview and resizing the parent manually as items are added. I set the anchors to the maximum size and adjust the sizeDelta.
public class MenuScript : MonoBehaviour
{
public int MenuItemCount;
public GameObject MenuItemPrefab;
public Transform MenuItemParent;
private RectTransform _rectTransform;
void Start()
{
_rectTransform = GetComponent<RectTransform>();
for (var i = 0; i <= MenuItemCount; i++)
{
GameObject instance = Instantiate(MenuItemPrefab, MenuItemParent, false);
instance.GetComponent<Text>().text = instance.name = "Item " + i;
float size = instance.transform.GetComponent<RectTransform>().sizeDelta.y;
TryExpandBy(size + 10);
}
}
private void TryExpandBy(float size)
{
var deltaY = _rectTransform.sizeDelta.y + size;
if (deltaY > 0) deltaY = 0;
_rectTransform.sizeDelta = new Vector2(_rectTransform.sizeDelta.x, deltaY);
}
}

RectTransform coordinates according to TextMesh Pro text size

I'm trying to create an InputField (TextMesh Pro) with a dynamic (its text content may vary) prefix.
This spectacular image should explain the goal.
https://imgur.com/a/qx1eXOa
So I set a TextMeshPro text to use as Prefix, and by script I was trying to "move" the TextArea accordingly.
The fact is, TextArea is a RectTransform, and I'm operating in a ScreenSpace render mode.
I was trying like this:
private TextMeshProGUI prefix;
private RecTransform textArea;
public void ChangePrefixTo(string newPrefix)
{
float oldWidth = prefix.preferredWidth;
prefix.text = newPrefix;
float newWidth = prefix.preferredWidth;
Vector2 newPos = new Vector2();
newPos.x = textArea.position.x + (newWidth - oldWidth);
newPos.y = textArea.position.y;
textArea.position = newPos;
}
, but the textArea gets shot into the stars.
How can I map the RectTransform position according to the size of a TextMeshPro text?
Thanks for the help and long live the whales
Instead of using a script to resize your prefix, you can group both of your elements in a Horizontal Layout Group, check only Width for Child Controls Size.
Add a Layout Element and set your Preferred Width to define the size of your TextArea.
The Prefix will scale according to his content, and it will push your text area as it grows.

Display loaded UI Image in Container with native size

I want to display UI logo images in their aspect ratio but in proper size that fit within its container. Already all logo images as per aspect ratio but few are too big or small compare to requirements.
At present this kind of thing happening:
Here is the code that I am using:
private void ShowGamePlayLogoViewed ()
{
for (int i = 0; i < DataCollection.companyDetailsList.Count; i++) {
Company company = DataCollection.companyDetailsList [i];
if (company.ViewedCounter > 0) {
GameObject companyItemObj = Instantiate (companyItemPref, gridViewContainer) as GameObject;
CompanyItem companyItem = companyItemObj.GetComponent<CompanyItem> ();
companyItem.companyId = company.CompanyId;
companyItem.UpdateCompanyLogo (company.CompanyLogo);
companyItem.UpdateCompanyName (company.CompanyName);
}
}
}
public void UpdateCompanyLogo (Sprite logoSprite)
{
logoImage.sprite = logoSprite;
logoImage.SetNativeSize ();
}
As you are seeing, logos overlapping the container. I want to display properly them in their respective containers also in aspect ratio too.
Let me clarify one more thing: all logos loaded from web server and they all are dynamic at a time, based on server data it will appear in mobile screen.
I have found solution through Unity Forum and I want to say thanks to #Hosnkobf for reply.
Here is the exact reply that worked for me properly:
adjust the image game object inside unity so that it has the height you are looking for. also adjust the anchors so that it scales with different resolutions properly.
Add an "AspectRatioFitter" component to the object. Make it "Height controls width".
Instead of logoImage.SetNativeSize (); do the following:
float aspectRatio = logoSprite.rect.width / logoSprite.rect.height;
var fitter = logoImage.GetComponent<UnityEngine.UI.AspectRatioFitter>();
fitter.aspectRatio = aspectRatio;
I hope this become useful to other members :)

Unity 5: how to zoom and translate an object from a grid layout to the center of the screen

I'm trying to create a scroll grid view in which every cell object is tapable.
When a cell object is tapped I want to scale and traslate it to the center of the screen and render it above other cells.
I was able to make it tapable and scale it in its position. Now I want to move the cell object to the center of the screen and render it above other cells.
I've tried many solutions but none of them works.
This is my hierarchy:
This is the grid in normal state:
This is the grid when a cell was tapped:
I'm populating the grid from a C# script dynamically.
void Populate()
{
GameObject cardContainerInstance, cardInstance;
foreach (var c in cardsCollection.GetAll())
{
if (c.IsOwned)
{
cardContainerInstance = Instantiate(cardContainer, transform);
cardInstance = cardContainerInstance.transform.Find("Card").gameObject;
var cardManager = cardInstance.GetComponent<CardManager>();
cardManager.card = c;
cardManager.AddListener(this);
}
else
{
Instantiate(cardSlot, transform);
}
}
}
public void OnCardClick(GameObject cardObject, Card card)
{
Debug.Log("OnCardClick " + card.name);
if (openedCard != null) {
if (openedCard.Number == card.Number)
{
CloseCard(openedCardObject);
}
else
{
CloseCard(openedCardObject);
OpenCard(cardObject, card);
}
}
else
{
OpenCard(cardObject, card);
}
}
void OpenCard(GameObject cardObject, Card card)
{
//cardObject.GetComponent<Canvas>().sortingOrder = 1;
var animator = cardObject.GetComponent<Animator>();
animator.SetTrigger("Open");
openedCard = card;
openedCardObject = cardObject;
}
void CloseCard(GameObject cardObject)
{
var animator = cardObject.GetComponent<Animator>();
animator.SetTrigger("Close");
openedCard = null;
openedCardObject = null;
}
I can't figure out how to move the cell to the center and render it above others.
Note that all is animated using an animator attached to the object itself.
Could anyone help me please? Thank you very much!
EDIT: more details
All cell object have the following hierarchy:
where:
CardContainer is an empty object added to use animator on Card child object
Card is the object itself that has a script, a canvas renderer and an animator
StatsImage is the object that slide out when the card is tapped
Image is a calssic UIImage with Image script, Shadow script and canvas renderer
Other component are simple texts.
EDIT: fix in progress
Trying to apply this suggestions I was able to manage the rendering order (as you see on the image below) but it seems that prevent touch events to be detected on the game object.
I've added a GraphicsRaycaster too and now the bottom horizontal scroll view scrolls again but only if I click and drag a card.
Moreover, with the GraphicsRaycaster, the main grid card still are not clickable and it's possible to open the card only if it is behind the bottom panel (if I click on the red spot in the image below the card behind the panel receives che click)
This is the CardContainer at runtime(note that I'm attaching new Canvas and GraphicsRaycaster on the CardContainer, which is the "root" element):
You didn't clarify whether you are using a sprite renderer or some other method but here is an answer for each.
Sprite renderer:
this the simple one. In each sprite renderer, there is a variable called "sortingOrder" in script and "Order in layer" in the inspector. sprite renderer with sorting Orders that are higher is rendered first. All you would need to do is call:
cardObject.GetComponent<SpriteRenderer>().sortingOrder = 1;
when you click the card, and
cardObject.GetComponent<SpriteRenderer>().sortingOrder = 0;
when you unclick it. I hope that makes sense!
Other Method:
this one is a bit harder and I would suggest that you switch to sprite renderers and it will be much easier and more stable down the road, but I can understand if you have already written a lot of scripts and don't want to go back and change them.
Anyway, all you will need to do Is create two layers: cardLower and cardUpper. then create a new camera and call it topCamera. now under the top camera object in the inspector, change the culling mask (it's near the top) and make sure cardUpper is selected. then change the Clear flags (first one) to "Don't Clear" finally change the depth to 0 (if that doesn't work change it to -2). Now objects in the cardUpper will always be rendered above everything else. You can change the layer through script with
cardObject.layer = "cardUpper"
or
cardObject.layer = "cardLower"
I hope that helps!
Ok, so its pretty simple. So you are going to want to add another canvas component to the game object, and check the override sorting to true. Then use
cardObject.GetComponent<Canvas>().sortingOrder = 1;
to place it in the front and
cardObject.GetComponent<Canvas>().sortingOrder = 0;
to put it in the back.
you are also going to need to put a GraphicsRaycaster on to each of the cardObjects
Ignore my other answer about sprite renderers, they are not needed here

Unity proper way of adding display views

I just wanted to ask what is the proper way to create and display a view on Unity. I'm just a beginner on this and just watched recently tutorials on how to script and learned about creating GUI on the fly which includes buttons, edit text boxes and other view but not sure on how should I really implement it the way it is optimized and won't affect the applications performance. What I tried so far is to create an editText wherein I set it on the MainCamera for display which is I targeted to be reusable so that in case I need to add more editText on the app I can just drag and drop the script. Here's the code so far:
using UnityEngine;
using System.Collections;
public class EditText : MonoBehaviour {
public int width = 150;
public int height = 25;
public int x_position = 0;
public int y_position = 0;
public string text = "Hello World";
public Position position = Position.unset;
public int text_size = 15;
public enum Position{unset,center_screen, center_vertical, center_horizontal};
void OnGUI () {
setPosition ();
GUI.skin.textArea.fontSize = text_size;
GUI.color = Color.red;
}
private void setPosition(){
switch (position) {
case Position.center_screen:
GUI.TextArea (new Rect (Screen.width/2 - width/2, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_vertical:
GUI.TextArea (new Rect (x_position, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_horizontal:
GUI.TextArea (new Rect (Screen.width/2 - width/2, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
default:
GUI.TextArea (new Rect (x_position, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
}
}
}
Question is am I doing this right or should I stop and use other implementation? Since I really intended it to be as reusable just like the Android Views. Also if there is any other library or scripts I can use to achieve this so that I'm not reinventing the wheel for this?
On the side note I also searched the NGUI although I'm not that sure on if this will fit my needs or not. Since when I tried creating a UILabel the component has only few options where I am not really sure on how I supposed to use it.
Question: Am I doing this right or should I stop and use other implementation?
It depends. Your implementation is simple but working. If you need more fancy UI, you might consider:
NGUI
NoesisGUI
Unity 4.6+ or Unity 5
According to Unity official blog, the "new GUI system is getting really close and it’ll be included in Unity 4.6, which will also be the last major update in the Unity 4 cycle".
I would prefer the last one, Unity 4.6 or Unity 5, as it is free and official from Unity, and the support and community are the big asset for you!
For your current implementation, I think you can make it even better, without using:
GUI.TextArea (new Rect (...)); // Not the best way
Instead try using:
GUILayout.BeginHorizontal ();
{
GUILayout.FlexibleSpace ();
//label etc., this guarantees centered in your UI and resolution independent.
GUILayout.XXX (...);
GUILayout.FlexibleSpace ();
}
GUILayout.EndHorizontal ();
Interesting links:
http://docs.unity3d.com/ScriptReference/GUILayout.html
GUI Layout tutorial
Unity's GUI system is far from perfect, but it's being improved incrementally. It's a good solution for interfaces with few simple elements. When using Unity's GUI system, i've generally set up each menu or 'display' separately. I never designed the UI elements in a modular fashion in the Unity system. I've not been in a situation where setting the 'Rect' of an element hasn't met my needs of manipulation. I can't say much about the performance of Unity's GUI system apart from that i've never noticed it's impact.
NGUI, like Unity is designed to be modular. To create the ui element that you desire might require you to piece together various scripts. For example an input field would require UILabel, UIInput script and a BoxCollider. Using all the scripts included in NGUI i've been able to create some pretty impressive interface prefabs. Being able to structure my interface visually in the scene view has been helpful as well.
These are the two UI systems i've used and have found uses for both.