Given a Text, get the rect of a word within that Text

Hey folks. Been searching for a solution to this for a bit with no luck and was wondering if anyone might have any ideas.

Basically, given a Text object in a screen-space canvas with some message in it - e.g. “Steve gave a bucket to Tom”, how can I find the screen rect of the word “bucket” in this Text object? The purpose of this would be to put an invisible button there to make words “clickable” within a text object.

I’ve already taken a look at the Text.cachedTextGenerator, and I think I can get the width and height of the word through GetPreferredWidth() and GetPreferredHeight() respectively, but I’m no closer to figuring out the starting position of the word.

Any ideas?

I would look at the inputfield ui code as Unity has code in there to handle setting up their selection box (for when you do copy, cut, delete after selecting). That should give you an idea of how they are handling it and may help you there.

There is also an asset on the store called hypertext that could do what you want, however it’s not a free asset.

You can use cachedTextGenerator.verts / GetVertices / GetVerticesArray, knowing that 1 character = 1 quad = 4 vertices. If bucket is the substring (14, 6) of your message, and the quad vertices are described from the top-left, clockwise. Therefore, the ‘b’ of bucket is at position 14 and the ‘t’ of bucket is at position 19. In addition, the bottom-left vertex of ‘b’ quad is at position 14 * 4 + 3 in the UIVertex list, and the top-right of ‘t’ quad is at position 19 * 4 + 1.

So you should consider the vertices indexed 14 * 4 + 3 and 19 * 4 + 1, which correspond to the min/max of the rect containing the word “bucket” in local coordinates from the Text pivot.

Use IndexOf to get the appropriate substring index if you use strings you cannot predict, and adapt your calculation with considering the Text graphic pivot position. This should give you what you want.

Remember to handle special cases such as the Text rect being too small, resulting in cropped text (the cached generator should return you fewer vertices than expected).

I learned those things while working on a patch for Unity-UI-Extensions TextPic.cs

Like huulong said, you could work through the vertex data. Or, if your text is static, you could manually place a collider. This can work for a simple case, but gets unwieldy for more complex situations, like dynamic text or multiple clickable areas in a block of text. Once you get there, using an existing tool like TextMesh Pro is much faster and more convenient, and offers additional benefits too. (I work with Stephan on TextMesh Pro.)