Change color of a single word

I’m currently working a game where you can click on individual words in a Text Mesh Pro.
When a word has been clicked, I need it to change color.

I’m already able to figure out what word was pressed and to find out the characterindexes of the relevant characters. Old post (2014) regarding text mesh pro suggested to change the color property of the individual vertices of the character in order to change the color of the word. (http://digitalnativestudios.com/forum/index.php?topic=253.0) Unfortunately the approach outlined there isn’t available any longer because some of the necessary fields are no longer exposed (or changed?).

I have tried to set the colors as followed instead

TMP_WordInfo info = _text.textInfo.wordInfo[wordIndex];

for (int i = 0; i < info.characterCount; ++i)
{
    TMP_CharacterInfo cInfo = _text.textInfo.characterInfo[info.firstCharacterIndex + i];

    cInfo.vertex_BL.color = myColor32;
    cInfo.vertex_BR.color = myColor32;
    cInfo.vertex_TL.color = myColor32;
    cInfo.vertex_TR.color = myColor32;
}

This doesn’t have any effect though.
Any ideas?

2 Likes

Take a look at the example 23 - Animating Vertex Attributes and the script used in that example.

Also take a look at example 12 - Link Example which tints words as you mouse over them.

The scripts used in those two examples should provide the additional information you need to implement what you need.

Keep me posted on your progress.

2 Likes

It works! Thanks!
Example 12 contained the magic needed :slight_smile:

Here is my solution

TMP_WordInfo info = _text.textInfo.wordInfo[wordIndex];
for (int i = 0; i < info.characterCount; ++i)
{
    int charIndex = info.firstCharacterIndex + i;
    int meshIndex = _text.textInfo.characterInfo[charIndex].materialReferenceIndex;
    int vertexIndex = _text.textInfo.characterInfo[charIndex].vertexIndex;
   
    Color32[] vertexColors = _text.textInfo.meshInfo[meshIndex].colors32;
    vertexColors[vertexIndex + 0] = myColor32;
    vertexColors[vertexIndex + 1] = myColor32;
    vertexColors[vertexIndex + 2] = myColor32;
    vertexColors[vertexIndex + 3] = myColor32;
}

_text.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
6 Likes

Just adding my solution too thanks diekeure - yours helped me!

for (int i = 0; i < myText.textInfo.wordCount; i++)
{
TMP_WordInfo wInfo = myText.textInfo.wordInfo*;*
for (int j = 0; j < wInfo.characterCount; j++)
{
yield return StartCoroutine(waitWithDuration(.2f));
int characterIndex = wInfo.firstCharacterIndex + j;
int meshIndex = myText.textInfo.characterInfo[characterIndex].materialReferenceIndex;
int vertexIndex = myText.textInfo.characterInfo[characterIndex].vertexIndex;
Color32[ ] vertexColors = myText.textInfo.meshInfo[meshIndex].colors32;
vertexColors[vertexIndex + 0] = BLUE;
vertexColors[vertexIndex + 1] = BLUE;
vertexColors[vertexIndex + 2] = BLUE;
vertexColors[vertexIndex + 3] = BLUE;

}
myText.UpdateVertexData(TMP_VertexDataUpdateFlags.All);

Hi guys!

What about :

<color=#FF0000> blablabla </color> ?

I’ve tried myself and it works perfectly. The longest step was to find the # charachter on my keyboard.

PS : On the other hand, the code you posted didn’t work for me…

42 Likes

Hey ! … That’s pretty good.

9 Likes

Hey guys,
I now it is a while since somebody posted here. I am quite new to unity and C#. Actually I never had anything to do with coding but recently I decided to work on an app. This app requires that a word changes the color when I hover over any character of the word and changes to another color when I click on the chosen word.

I created a text - TextMeshPro and created a new script in the inspector of the text. Then I opened the script file.

Could someone explain where do I need to copy paste the codes above? The initial code looks like this.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class changeColor : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{

}

// Update is called once per frame
void Update()
{

}
}

If you’re new to coding but understand UV and vertices then you might understand how textmesh pro colors the words. If not then the script is quite advanced I’d say. But, there’s a way. There is a script called “Text_Selector_B.cs” that gets downloaded when you download Examples of TextMeshPro From 'Package Manager. Fortunately, it works exactly as you wanted. When you hover your mouse on a word, it changes color and mouse is not hovered , word returns to original color. You can change from hover to mouse click in few minutes. you need to put that Script on the same Gameobject that contains TextMeshProUGUI component. Then it’ll surely work. Don’t forget to check out example "link interaction " if you get confused.

public static class StringExtensions
{
    public static string AddColor(this string text, Color col) => $"<color={ColorHexFromUnityColor(col)}>{text}</color>";
    public static string ColorHexFromUnityColor(this Color unityColor) => $"#{ColorUtility.ToHtmlStringRGBA(unityColor)}";
}

//Usage
TextMeshProUGUI SomeTMProText;

SomeTMProText.SetText($"" +
            $"{"H".AddColor(Color.red)}" +
            $"{"E".AddColor(Color.blue)}" +
            $"{"L".AddColor(Color.green)}" +
            $"{"L".AddColor(Color.white)}" +
            $"{"O".AddColor(Color.yellow)}");

The AddColor method also works for adding color to Debug logs.

9 Likes

Hello, I’m currently trying to do the same thing but in a different way… I basically want it so the a word is highlighted with no mouse inputs and then after a failed event or correct event it would change the color of the word its currently on accordingly. I’ve been reading everything and even tried putting in the code provided above but it simply doesnt work… Is there anyone that can help?

1 Like

Wow, thanks man!
Holy moley, i have been making this waaaaaaaay too hard!!

Trying to do a letter-by-letter text reveal effect but this no longer seems to work in 2022. Text color simply doesn’t change

3 Likes

Take a look at the example “Animating Vertex Attributes” and related scripts included in the TMP Examples & Extras. The VertexColorCycler.cs script changes the color per characters but can easily be modified to modify the color per word. Basically instead of using the textInfo.characterInfo[ ], you would access the textInfo.wordInfo[index] to lookup the index of the first and last character of each word and then just like the script does modify the appropriate vertex colors.

I wonder why the answer here is a little complicated. I found that there is no need to get the materialReferenceIndex.
Here is my code:

private void ChangeColor(TextMeshProUGUI textMeshPro, int characterIndex, Color color)
{
    textMeshPro.ForceMeshUpdate();
    Color[] colors = textMeshPro.mesh.colors;
    colors[4 * characterIndex] = color;
    colors[4 * characterIndex + 1] = color;
    colors[4 * characterIndex + 2] = color;
    colors[4 * characterIndex + 3] = color;
    textMeshPro.mesh.colors = colors;
    textMeshPro.UpdateGeometry(textMeshPro.mesh, 0);
}

The only one of these solutions that works for me is the one using the “” tags. Nothing else I try to do seems to have any effect on the text at all.

1 Like

It works for me if I put it in the Update section. I tried the Start() section and it did nothing.

Ha, neat!
Note: you can set this in the inspector in the tex imput field or in code

The original solution usually doesn’t work, but can be updated to work.

The key thing is that TMP behind the scenes silently deletes most/all your changes before the end of the frame :frowning: by design (if I remember correctly: this is a deliberate (but very confusing) performance optimization). It’s hard to predictable unless you’ve read the source code / dived deep into this, but most commonly: if you change the text (or anything else) during this frame then your color changes will get wiped.

From @better_walk_away 's post, the key line is:

textMeshPro.ForceMeshUpdate();

… after making any other changes (e.g. changing the value of ‘.text’) and before making your color changes.