I’m trying to implement text appearing char by char to get a visual novel style story telling.
The code example in the wiki doesn’t work for me because this doesn’t take into account word width, and when you reach the end of a Text component width the whole word jump to the beginning of the next line. I need to know the width of the word in advance so I can decide if the first character of that word will start at the next line or the current line.
For this, I’m using the metrics provided by the CharacterInfo structure but I’m getting all zeros even for common ascii characters. I will elaborate, this is a simplified version of the problematic code:
Text text = mGUIText.GetComponent<Text> (); // mGUIText is a GameObject
CharacterInfo cinfo;
Font font = text.font;
And then, inside a loop:
char c = str*; // str is a string containing the dialogue*
font.GetCharacterInfo (c, out cinfo, text.fontSize, text.fontStyle);
I cannot properly calculate the width of words or lines of text because cinfo.advance and cinfo.width are always zero.
I found a solution. Per this question: http://answers.unity3d.com/questions/1071345/inconsistent-results-with-fontgetcharacterinfo.html
It seems that a font metrics is know by Unity only after some text that uses that font got actually rendered. Maybe Unity generates the texture containing the glyphs on the go, as I don’t see these textures on my filesystem, I would bet that how font rendering is implemented.
Game engines, and Unitys seems not to be the exception, package as many glyphs as it can in a single texture, this reduces texture switching during rendering that are considered a slow operation for real time rendering, so the engine can render many characters without requiring a texture switch. Same concept as packing sprites efficiently in as few texture atlases as you can.
So here is how I solved it, I won’t post my implementation but I will describe the process:
- Using the editor, create the main Canvas of your GUI system and then drop the Text that you will use as the dialog box to tell your story in visual novel style. Tweak its bounding rectangle to switch your project.
- Then on the script: first set the whole text of a single dialogue in a single assignment to the text property of the Text component.
- Call Canvas.ForceUpdateCanvases(); It’s a static function so just copy and paste that code, you don’t need a Canvas instance.
- Then clear all the text of the Text component by setting it to an empty string “”.
- As everything happened in a single frame, the player won’t see the Text component filled with the full dialogue, because you set it and cleared it in a single Update(). At least so far I didn’t see it so using a hidden Text component like ActualDog suggests seems unnecessary.
- Finally, proceed to add char by char. The code to know in advance the word width is easy to implement now that CharacterInfo contains what you need.
this issue found in 2017 1.2 also. Resetting the UI.text value and setting the UI.text value → work…
Thanks @Lao2211