Get position of specific letter in UI Text

Is there any way to get the position of a specific letter (or any part of the string) in a UI text? In World Space, Screen Space, Canvas Space, whatever.

Say I have text that can be “Level 1” or “Level 1000”. It’s middle-aligned so the letter L can be anywhere on the screen, but I want to move a GameObject right beside the L. How would I find that?

This is using Unity’s UI canvas. Specifically with Screen Space - Overlay, but ideally I’d like a solution that works regardless of screen space/world space type.

Thanks!

Hi Here is the scriptsnippet which will help you find exact letter position in Unity UI Text.

public class TextTest : MonoBehaviour
{
	public Text textComp;
	public int charIndex;
	public Canvas canvas;

	void PrintPos ()
	{
		string text = textComp.text;

		if (charIndex >= text.Length)
			return;

		TextGenerator textGen = new TextGenerator (text.Length);
		Vector2 extents = textComp.gameObject.GetComponent<RectTransform>().rect.size;
		textGen.Populate (text, textComp.GetGenerationSettings (extents));

		int newLine = text.Substring(0, charIndex).Split('

‘).Length - 1;
int whiteSpace = text.Substring(0, charIndex).Split(’ ').Length - 1;
int indexOfTextQuad = (charIndex * 4) + (newLine * 4) - 4;
if (indexOfTextQuad < textGen.vertexCount)
{
Vector3 avgPos = (textGen.verts[indexOfTextQuad].position +
textGen.verts[indexOfTextQuad + 1].position +
textGen.verts[indexOfTextQuad + 2].position +
textGen.verts[indexOfTextQuad + 3].position) / 4f;

			print (avgPos);
			PrintWorldPos (avgPos);
		}
		else {
			Debug.LogError ("Out of text bound");
		}
	}

	void PrintWorldPos (Vector3 testPoint)
	{
		Vector3 worldPos = textComp.transform.TransformPoint (testPoint);
		print (worldPos);
		new GameObject ("point").transform.position = worldPos;
		Debug.DrawRay (worldPos, Vector3.up, Color.red, 50f);
	}

	void OnGUI ()
	{
		if (GUI.Button (new Rect (10, 10, 100, 80), "Test"))
		{
			PrintPos ();
		}
	}
}[82165-findletterposinuitext.zip|82165]

Note: This logic works pretty well with any font and any text properties. Attached unity package to show same script sample.

Tested in : Unity 5.4.0f3
@Sujil-V-S Try this…

@Halleester and anyone else who needs this to work with the canvas set to scale with screen size:

simply divide the position returned for a character by the canvas.scaleFactor

worldPos /= canvas.scaleFactor

and it should work fine. I just got it working myself.

@Halleester, if you’re using this on a canvas with a canvas scaler component, you need to divide it by the scale factor. @hengde’s solution won’t actually work due to the canvas scaler being broken, canvas.scalefactor will always return 1 since it takes a frame to get the scale information.
To fix this store a variable that either gets defined after the scale value has initalized (one frame will do) or set it in an update function.

float screen_scale;
 
 void Update()
    {
        screen_scale = canvas.scaleFactor;
    }

Then I had to divide the scalefactor in the actual returned value.

  return PrintWorldPos(avgPos / screen_scale);

For some reason, dividing it by the screen scale didn’t work when I added into the ‘printworldpos’ function.

Thanks

Guys if you looking for text mesh pro version of this code i have working one . It is like this

public GameObject GetPositionOfLastLetterAsGameObject(TextMeshProUGUI tmp_text)
{

    tmp_text.ForceMeshUpdate();

    Vector3[] vertices = tmp_text.mesh.vertices;
    TMP_CharacterInfo charInfo = tmp_text.textInfo.characterInfo[tmp_text.textInfo.characterCount - 1];
    int vertexIndex = charInfo.vertexIndex;

    Vector2 charMidTopLine = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, (charInfo.bottomLeft.y + charInfo.topLeft.y) / 2);
    Vector3 worldPos = tmp_text.transform.TransformPoint(charMidTopLine);

    GameObject charPositionGameObj = new GameObject("PositionOfLastChar");
    charPositionGameObj.transform.position = worldPos;

    return charPositionGameObj;
}