Hyperlinks in Unity UI using Text Mesh Pro

Well, the 2018 Global Game Jam is around the corner in only two weeks. This year will be the second year I will be participating, creating a game in only 48 hours with a small team of devs. So, in preparation for the jam I am sharing a script I will likely be using during the jam. A common task during a game jam is to include a credits page with hyperlinks attributing any resources you have used, or linking back to your own pages. Unity’s game jam menu template doesn’t include an example of how to do this however and you might have noticed that Unity’s UI Text component doesn’t provide any functionality for a user to interact with text, even if it’s only to detect a word being clicked – so creating a hyperlink is actually a little less straightforward that you might assume.

Text Mesh Pro is an asset that adds a lot of extra functionality for displaying, stylizing and interacting with text over the existing UI Text component. Last year the asset and it’s developer joined Unity, making the asset free for all developers. I modified one of the TMP’s provided examples to get hyperlink functionality in my own game prototypes. You can find a quick drag-and-drop script to get this same functionality here.

TMP has html-like tags that you can use to markup the text you enter. Of particular interest is the link tag which can be used to easily identify text from code and tag it with additional data. It doesn’t have to be used for hyperlinks, but that’s what I’ll use it for in this example.

After adding my OpenHyperlinks component you get functionality to highlight links on mouse over and open them in your browser on click.

To specify a hyperlink you add the link tag and specify the url in it’s link data (id).

To get the main functionality all we need is a IPointerClickHandler callback, Application.OpenURL and TMP’s FindIntersectingLink method:

[RequireComponent(typeof(TextMeshProUGUI))]
public class OpenHyperlinks : MonoBehaviour, IPointerClickHandler {

    public void OnPointerClick(PointerEventData eventData) {
        int linkIndex = TMP_TextUtilities.FindIntersectingLink(pTextMeshPro, Input.mousePosition, pCamera);
        if( linkIndex != -1 ) { // was a link clicked?
            TMP_LinkInfo linkInfo = pTextMeshPro.textInfo.linkInfo[linkIndex];

            // open the link id as a url, which is the metadata we added in the text field
            Application.OpenURL(linkInfo.GetLinkID());
        }
    }
}

 

We can also change the link text to a different color when the cursor is over it, just like a normal hyperlink, to give feedback to the user that it is clickable. To achieve this we need to iterate over each character and update its material’s colors if it’s visible. Invisible characters aren’t included in the character count and so will cause us to update the wrong character colors if we don’t handle that case. We will also save the original colors so that we can restore them later after the cursor is no longer over the text. Nothing particularly difficult.

List<Color32[]> SetLinkToColor(int linkIndex, Color32 color) {
    TMP_LinkInfo linkInfo = pTextMeshPro.textInfo.linkInfo[linkIndex];

    var oldVertColors = new List<Color32[]>(); // store the old character colors

    for( int i = 0; i < linkInfo.linkTextLength; i++ ) { // for each character in the link string
        int characterIndex = linkInfo.linkTextfirstCharacterIndex + i; // the character index into the entire text
        var charInfo = pTextMeshPro.textInfo.characterInfo[characterIndex];
        int meshIndex = charInfo.materialReferenceIndex; // Get the index of the material / sub text object used by this character.
        int vertexIndex = charInfo.vertexIndex; // Get the index of the first vertex of this character.

        Color32[] vertexColors = pTextMeshPro.textInfo.meshInfo[meshIndex].colors32; // the colors for this character
        oldVertColors.Add(vertexColors.ToArray());

        if( charInfo.isVisible ) {
            vertexColors[vertexIndex + 0] = color;
            vertexColors[vertexIndex + 1] = color;
            vertexColors[vertexIndex + 2] = color;
            vertexColors[vertexIndex + 3] = color;
        }
    }

    // Update Geometry
    pTextMeshPro.UpdateVertexData(TMP_VertexDataUpdateFlags.All);

    return oldVertColors;
}

 

And that’s it! I hope you find this to be a useful starter if you want to interact with your text in Unity or you wanted some quick hyperlink functionality for a game jam. Till next time.