Hello,
For our game, we want to allow dialogue to have various text effects at different points. For example, if a character is scared some of their dialogue may jitter, or if they’re taunting the text might wave. To accomplish this, I wrote a custom parser that would take formatted text and get letter indices from it.
For example:
If I type the text <shake>These words shake.</shake> These words don't do anything. <wave>And these words wave.</wave>
, the script would recognize the starting and ending indices of each group of tags. (In this case, there would be a “ShakeText” object starting at 0 and ending around 18 or so.)
Next, I want to push this information to the TextMesh Pro object itself so the relevant vertices can be modified. For the sake of simplicity here’s only the part of the coroutine that runs for the shaking letters (worked out using the TextMesh Pro example code):
public IEnumerator ShakeText(List<int> shakeIndices, List<int> waveIndices) {
textMesh.ForceMeshUpdate();
TMP_TextInfo textInfo = textMesh.textInfo;
Vector3[][] copyOfVertices = new Vector3[0][];
hasTextChanged = true;
TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData();
Vector3[] cachedVertexInfo = cachedMeshInfo[textMesh.textInfo.characterInfo[0].materialReferenceIndex].vertices;
float g = 0f; // used for the sinewave
while (true) {
foreach (int index in shakeIndices) {
if (hasTextChanged)
{
if (copyOfVertices.Length < textInfo.meshInfo.Length)
copyOfVertices = new Vector3[textInfo.meshInfo.Length][];
for (int i = 0; i < textInfo.meshInfo.Length; i++)
{
int length = textInfo.meshInfo[i].vertices.Length;
copyOfVertices[i] = new Vector3[length];
}
hasTextChanged = false;
}
if (!textMesh.textInfo.characterInfo[index].isVisible) {
continue; // dont need to shake it if its not visible!
}
Debug.Log("shake: " + textMesh.textInfo.characterInfo[index].character.ToString());
float modX = Random.Range(-shakeAmount,shakeAmount);
float modY = Random.Range(-shakeAmount, shakeAmount);
Vector3 modifier = new Vector3(modX, modY, 0f);
int materialIndex = textMesh.textInfo.characterInfo[index].materialReferenceIndex;
Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices;
int vertexIndex = textInfo.characterInfo[index].vertexIndex;
for (int i = 0; i < textMesh.textInfo.meshInfo.Length; i++) {
copyOfVertices[materialIndex] = textMesh.textInfo.meshInfo[i].mesh.vertices;
}
copyOfVertices[materialIndex][vertexIndex + 0] = sourceVertices[vertexIndex + 0] + modifier;
copyOfVertices[materialIndex][vertexIndex + 1] = sourceVertices[vertexIndex + 1] + modifier;
copyOfVertices[materialIndex][vertexIndex + 2] = sourceVertices[vertexIndex + 2] + modifier;
copyOfVertices[materialIndex][vertexIndex + 3] = sourceVertices[vertexIndex + 3] + modifier;
Debug.Log(textMesh.textInfo.meshInfo[materialIndex].mesh.vertices[0]);
Debug.Log(textMesh.textInfo.meshInfo[materialIndex].mesh.vertices[1]);
Debug.Log(textMesh.textInfo.meshInfo[materialIndex].mesh.vertices[2]);
Debug.Log(textMesh.textInfo.meshInfo[materialIndex].mesh.vertices[3]);
Debug.Log("-------");
for (int i = 0; i < textMesh.textInfo.meshInfo.Length; i++) {
textMesh.textInfo.meshInfo[i].mesh.vertices = copyOfVertices[i];
textMesh.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
}
}
yield return new WaitForSeconds(0.1f);
}
}
By itself, this code works okay - there is a notable frame rate drop, but the text animation itself looks good. I have run into a bigger issue, however, when attempting to do the “typewriter” effect at the same time as this. The shake animation will not run fully until the “typing” is complete.
The typing effect itself I accomplish by incrementing the textMesh.maxVisibleCharacters
property by one every few fractions of a second, via a function in my script DialogueParse.cs (same one that transforms the vertices) that is called from OverworldDialogueEngine.cs (one that regulates dialogue flow).
Does anyone know why this is happening, and how I can fix it? (Additionally, if there is a more performant way of accomplishing this it would be very helpful to hear.)
In case the information I provided above wasn’t enough, here’s the full code of both scripts that play a part in the dialogue process:
DialogueParse.cs - used for parsing raw dialogue text and transforming the TextMesh Pro object’s vertices: https://drive.google.com/open?id=1dQjH-va8Hked9c_x3vuNckyMvVhGtijL
OverworldDialogueEngine.cs - used for regulating the flow of dialogue, calling for the “typewriter” effect: https://drive.google.com/open?id=1EX1IKSfif63V-tk8zKqTHwf3AEd3F0vh
Please let me know if there’s any more information you need. I’m happy to supply it!
Thanks,
Malcolm