Search Unity

TextMesh Pro Change color of a single word

Discussion in 'UGUI & TextMesh Pro' started by diekeure, Jul 2, 2018.

  1. diekeure

    diekeure

    Joined:
    Jan 25, 2013
    Posts:
    221
    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

    Code (CSharp):
    1. TMP_WordInfo info = _text.textInfo.wordInfo[wordIndex];
    2.  
    3. for (int i = 0; i < info.characterCount; ++i)
    4. {
    5.     TMP_CharacterInfo cInfo = _text.textInfo.characterInfo[info.firstCharacterIndex + i];
    6.  
    7.     cInfo.vertex_BL.color = myColor32;
    8.     cInfo.vertex_BR.color = myColor32;
    9.     cInfo.vertex_TL.color = myColor32;
    10.     cInfo.vertex_TR.color = myColor32;
    11. }
    This doesn't have any effect though.
    Any ideas?
     
    dan_ginovker and FernandoHC like this.
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    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.
     
    diekeure and FernandoHC like this.
  3. diekeure

    diekeure

    Joined:
    Jan 25, 2013
    Posts:
    221
    It works! Thanks!
    Example 12 contained the magic needed :)

    Here is my solution

    Code (CSharp):
    1. TMP_WordInfo info = _text.textInfo.wordInfo[wordIndex];
    2. for (int i = 0; i < info.characterCount; ++i)
    3. {
    4.     int charIndex = info.firstCharacterIndex + i;
    5.     int meshIndex = _text.textInfo.characterInfo[charIndex].materialReferenceIndex;
    6.     int vertexIndex = _text.textInfo.characterInfo[charIndex].vertexIndex;
    7.    
    8.     Color32[] vertexColors = _text.textInfo.meshInfo[meshIndex].colors32;
    9.     vertexColors[vertexIndex + 0] = myColor32;
    10.     vertexColors[vertexIndex + 1] = myColor32;
    11.     vertexColors[vertexIndex + 2] = myColor32;
    12.     vertexColors[vertexIndex + 3] = myColor32;
    13. }
    14.  
    15. _text.UpdateVertexData(TMP_VertexDataUpdateFlags.All);
     
  4. NatCou

    NatCou

    Joined:
    Jan 29, 2017
    Posts:
    26
    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);
     
  5. Alessandruus

    Alessandruus

    Joined:
    Apr 2, 2017
    Posts:
    1
    Hi guys!

    What about :

    Code (CSharp):
    1. <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...
     
  6. Argl

    Argl

    Joined:
    May 10, 2014
    Posts:
    14
    Hey ! ..... That's pretty good.
     
  7. ChrisShiRuiSi

    ChrisShiRuiSi

    Joined:
    Jan 6, 2021
    Posts:
    2
    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()
    {

    }
    }
     
  8. Raikir-i-sh

    Raikir-i-sh

    Joined:
    Aug 9, 2018
    Posts:
    13
    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.
     
  9. DevBeeBee

    DevBeeBee

    Joined:
    Sep 22, 2019
    Posts:
    1
    Code (CSharp):
    1.  
    2.  
    3. public static class StringExtensions
    4. {
    5.     public static string AddColor(this string text, Color col) => $"<color={ColorHexFromUnityColor(col)}>{text}</color>";
    6.     public static string ColorHexFromUnityColor(this Color unityColor) => $"#{ColorUtility.ToHtmlStringRGBA(unityColor)}";
    7. }
    8.  
    9. //Usage
    10. TextMeshProUGUI SomeTMProText;
    11.  
    12. SomeTMProText.SetText($"" +
    13.             $"{"H".AddColor(Color.red)}" +
    14.             $"{"E".AddColor(Color.blue)}" +
    15.             $"{"L".AddColor(Color.green)}" +
    16.             $"{"L".AddColor(Color.white)}" +
    17.             $"{"O".AddColor(Color.yellow)}");
    18.  
    19.  
    http://digitalnativestudios.com/textmeshpro/docs/rich-text/




    The AddColor method also works for adding color to Debug logs.
     
    Last edited: Feb 9, 2021
  10. Nicholas-Dannenberg

    Nicholas-Dannenberg

    Joined:
    Sep 25, 2018
    Posts:
    4
    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?
     
    ediit likes this.
  11. LordHeman

    LordHeman

    Joined:
    Mar 23, 2020
    Posts:
    2
    Wow, thanks man!
    Holy moley, i have been making this waaaaaaaay too hard!!
     
  12. ediit

    ediit

    Joined:
    Mar 17, 2018
    Posts:
    8
    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
     
  13. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    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.
     
  14. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    291
    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:
    Code (CSharp):
    1. private void ChangeColor(TextMeshProUGUI textMeshPro, int characterIndex, Color color)
    2. {
    3.     textMeshPro.ForceMeshUpdate();
    4.     Color[] colors = textMeshPro.mesh.colors;
    5.     colors[4 * characterIndex] = color;
    6.     colors[4 * characterIndex + 1] = color;
    7.     colors[4 * characterIndex + 2] = color;
    8.     colors[4 * characterIndex + 3] = color;
    9.     textMeshPro.mesh.colors = colors;
    10.     textMeshPro.UpdateGeometry(textMeshPro.mesh, 0);
    11. }
     
    Last edited: Sep 16, 2022
  15. jacobsahlmueller

    jacobsahlmueller

    Joined:
    Jan 8, 2020
    Posts:
    1
    The only one of these solutions that works for me is the one using the "<color>" tags. Nothing else I try to do seems to have any effect on the text at all.
     
    a436t4ataf likes this.
  16. GareGames

    GareGames

    Joined:
    May 12, 2022
    Posts:
    2
    It works for me if I put it in the Update section. I tried the Start() section and it did nothing.
     
  17. DucaDiMonteSberna

    DucaDiMonteSberna

    Joined:
    Jan 18, 2018
    Posts:
    79
    Ha, neat!
    Note: you can set this in the inspector in the tex imput field or in code
     
  18. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    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 :( 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:

    Code (CSharp):
    1. textMeshPro.ForceMeshUpdate();
    ... after making any other changes (e.g. changing the value of '.text') and before making your color changes.