IEnumerator TMPJitter(int start, int end, float AngleMultiplier, float CurveScale) { bool hasTextChanged; // We force an update of the text object since it would only be updated at the end of the frame. Ie. before this code is executed on the first frame. // Alternatively, we could yield and wait until the end of the frame when the text object will be generated. //m_TextMeshPro.ForceMeshUpdate(); yield return(null); TMP_TextInfo textInfo = m_TextMeshPro.textInfo; Matrix4x4 matrix; int loopCount = 0; hasTextChanged = true; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } // Cache the vertex data of the text object as the Jitter FX is applied to the original position of the characters. TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); while (true) { // Get new copy of vertex data if the text has changed. if (hasTextChanged) { // Update the copy of the vertex data for the text object. cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); hasTextChanged = false; } int characterCount = textInfo.characterCount; // If No Characters then just yield and wait for some text to be added if (characterCount < end - start) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = start; i <= end; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; // Skip characters that are not visible and thus have no geometry to manipulate. if (!charInfo.isVisible) { continue; } // Retrieve the pre-computed animation data for the given character. VertexAnim vertAnim = vertexAnim[i]; // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the cached vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; // Determine the center point of each character at the baseline. //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Determine the center point of each character. Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. // This is needed so the matrix TRS is applied at the origin for each character. Vector3 offset = charMidBasline; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; m_TextMeshPro.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(0.1f)); } }
IEnumerator AnimateDangling() { Matrix4x4 matrix; Vector3[] vertices; int loopCount = 0; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(DanglingRange.x, DanglingRange.y); vertexAnim[i].speed = Random.Range(DanglingSpeed.x, DanglingSpeed.y); } m_TextComponent.renderMode = TextRenderFlags.DontRender; while (loopCount < 10000) { m_TextComponent.ForceMeshUpdate(); vertices = m_TextComponent.textInfo.meshInfo[0].vertices; int characterCount = m_TextComponent.textInfo.characterCount; for (int i = 0; i < characterCount; i++) { // Setup initial random values VertexAnim vertAnim = vertexAnim[i]; TMP_CharacterInfo charInfo = m_TextComponent.textInfo.characterInfo[i]; // Skip Characters that are not visible if (!charInfo.isVisible) { continue; } int vertexIndex = charInfo.vertexIndex; Vector2 charMidTopline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, charInfo.topRight.y); // Vector2 charMidBasline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. Vector3 offset = charMidTopline; // Vector3 offset = charMidBasline; vertices[vertexIndex + 0] += -offset; vertices[vertexIndex + 1] += -offset; vertices[vertexIndex + 2] += -offset; vertices[vertexIndex + 3] += -offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); //Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 0, vertexAnim[i].angle), Vector3.one); //matrix = Matrix4x4.TRS(jitterOffset, Quaternion.identity, Vector3.one); //matrix = Matrix4x4.TRS(jitterOffset, Quaternion.Euler(0, 0, Random.Range(-5f, 5f)), Vector3.one); vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]); vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]); vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]); vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]); vertices[vertexIndex + 0] += offset; vertices[vertexIndex + 1] += offset; vertices[vertexIndex + 2] += offset; vertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } loopCount += 1; //m_TextComponent.mesh.vertices = vertices; //m_TextComponent.mesh.uv = m_TextComponent.textInfo.meshInfo[0].uvs0; //m_TextComponent.mesh.uv2 = m_TextComponent.textInfo.meshInfo[0].uvs2; //m_TextComponent.mesh.colors32 = m_TextComponent.textInfo.meshInfo[0].colors32; var textInfo = m_TextComponent.textInfo; for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; m_TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } //Debug.Log("Vertex Attributes Modified."); yield return(new WaitForSeconds(DangleRefresh)); } }
IEnumerator AnimateReveal() { Matrix4x4 matrix; Vector3[] vertices; int loopCount = 0; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(90f, 90f); vertexAnim[i].speed = Random.Range(1f, 3f); } m_TextComponent.renderMode = TextRenderFlags.DontRender; int direction = 1; m_TextComponent.ForceMeshUpdate(); vertices = m_TextComponent.textInfo.meshInfo[0].vertices; while (loopCount < 10000) { //m_TextMeshPro.ForceMeshUpdate(); //vertices = m_TextMeshPro.textInfo.meshInfo.vertices; int characterCount = m_TextComponent.textInfo.characterCount; for (int i = 0; i < characterCount; i++) { // Setup initial random values VertexAnim vertAnim = vertexAnim[i]; TMP_CharacterInfo charInfo = m_TextComponent.textInfo.characterInfo[i]; // Skip Characters that are not visible if (!charInfo.isVisible) { continue; } int vertexIndex = charInfo.vertexIndex; Vector2 charMidTopline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, charInfo.topRight.y); // Vector2 charMidBasline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. Vector3 offset = charMidTopline; // Vector3 offset = charMidBasline; float angle = 0; while (angle < 90) { vertices[vertexIndex + 0] += -offset; vertices[vertexIndex + 1] += -offset; vertices[vertexIndex + 2] += -offset; vertices[vertexIndex + 3] += -offset; matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 15 * direction, 0), Vector3.one); vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]); vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]); vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]); vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]); vertices[vertexIndex + 0] += offset; vertices[vertexIndex + 1] += offset; vertices[vertexIndex + 2] += offset; vertices[vertexIndex + 3] += offset; //m_TextComponent.mesh.vertices = vertices; //m_TextComponent.mesh.uv = m_TextComponent.textInfo.meshInfo[0].uvs0; //m_TextComponent.mesh.uv2 = m_TextComponent.textInfo.meshInfo[0].uvs2; //m_TextComponent.mesh.colors32 = m_TextComponent.textInfo.meshInfo[0].colors32; var textInfo = m_TextComponent.textInfo; for (int j = 0; j < textInfo.meshInfo.Length; j++) { textInfo.meshInfo[j].mesh.vertices = textInfo.meshInfo[j].vertices; m_TextComponent.UpdateGeometry(textInfo.meshInfo[j].mesh, j); } angle += 15; yield return(null); //vertexAnim[i] = vertAnim; } } loopCount += 1; direction *= -1; //Debug.Log("Vertex Attributes Modified."); yield return(new WaitForSeconds(0.1f)); } }
IEnumerator StraightLine(string text) { float height = 0; meshPro.text = text; meshPro.ForceMeshUpdate(); //メッシュ情報をキャシュー cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); Color32 c0 = tmpText.color; float terminalTime = 0; float lifeCycle = 10 + text.Length * 0.1f; float angle = 0; pingpongAngle = Mathf.Abs(pingpongAngle); pingpongAngleSpeed = Mathf.Abs(pingpongAngleSpeed); VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(pingpongAngle * 0.6f, pingpongAngle); vertexAnim[i].speed = Random.Range(pingpongAngleSpeed * 0.6f, pingpongAngleSpeed); } while (terminalTime < lifeCycle) { //文字をカメラに向いて /* * transform.LookAt(-Camera.main.transform.position, transform.position.normalized); * var wideScale = (Mathf.Abs(Camera.main.transform.localPosition.z) - EarthRadiu) * WideScaleFactor; * wideScale = Mathf.Min(wideScale, MaxWideScale); * transform.localScale = new Vector3(wideScale, wideScale, wideScale);*/ height += MoveUpdateInterval * spiralUpSpeed; /* * if (pingpongAngle != 0) * { * angle += MoveUpdateInterval * angleDirect * pingpongAngleSpeed; * if (angle>= pingpongAngle) * { * angleDirect = -1; * }else if (angle <= -pingpongAngle) * { * angleDirect = 1; * } * }*/ angle = Mathf.PingPong(height * pingpongAngleSpeed, pingpongAngle) - pingpongAngle / 2; for (int i = 0; i < textInfo.characterCount; i++) { int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; int vertexIndex = textInfo.characterInfo[i].vertexIndex; Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; VertexAnim vertAnim = vertexAnim[i % vertexAnim.Length]; vertAnim.angle = Mathf.PingPong(height * vertAnim.speed, vertAnim.angleRange) - vertAnim.angleRange / 2; /* * destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex] + new Vector3(-height, 0, 0); * destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] + new Vector3(-height, 0, 0); * destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] + new Vector3(-height, 0, 0); * destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] + new Vector3(-height, 0, 0); */ var forward = Vector3.Cross((sourceVertices[1] - sourceVertices[vertexIndex]).normalized, (sourceVertices[vertexIndex + 2] - sourceVertices[vertexIndex]).normalized); var averagePosition = (sourceVertices[vertexIndex] + sourceVertices[vertexIndex + 1] + sourceVertices[vertexIndex + 2] + sourceVertices[vertexIndex + 3]) / 4; destinationVertices[vertexIndex + 0] = averagePosition + Quaternion.AngleAxis(vertAnim.angle, forward) * (sourceVertices[vertexIndex] - averagePosition) + new Vector3(-height, 0, 0); destinationVertices[vertexIndex + 1] = averagePosition + Quaternion.AngleAxis(vertAnim.angle, forward) * (sourceVertices[vertexIndex + 1] - averagePosition) + new Vector3(-height, 0, 0); destinationVertices[vertexIndex + 2] = averagePosition + Quaternion.AngleAxis(vertAnim.angle, forward) * (sourceVertices[vertexIndex + 2] - averagePosition) + new Vector3(-height, 0, 0); destinationVertices[vertexIndex + 3] = averagePosition + Quaternion.AngleAxis(vertAnim.angle, forward) * (sourceVertices[vertexIndex + 3] - averagePosition) + new Vector3(-height, 0, 0); var newVertexColors = textInfo.meshInfo[materialIndex].colors32; //各キャラクターの頂点の色を頂点透明度を高さの元ついてスムーズに変更 if (textInfo.characterInfo[i].isVisible) { float alpha = 1f; float characterHeight = Mathf.Max(-destinationVertices[vertexIndex + 0].x, 0); //高さが一番下未満と一番上を超えた場合。 if (characterHeight <= displayStartHeight || characterHeight > vanishEndHeight) { alpha = 0; } //displayStartHeightからdisplayEndHeight徐々に表示 else if (characterHeight > displayStartHeight && characterHeight < displayEndHeight) { alpha = (characterHeight - displayStartHeight) / (displayEndHeight - displayStartHeight); } //vanishStartHeightからvanishEndHeight徐々に非表示 else if (characterHeight > vanishStartHeight && characterHeight < vanishEndHeight) { alpha = (vanishEndHeight - characterHeight) / (vanishEndHeight - vanishStartHeight); } c0 = new Color32(newVertexColors[vertexIndex].r, newVertexColors[vertexIndex].g, newVertexColors[vertexIndex].b, (byte)(alpha * 255)); newVertexColors[vertexIndex + 0] = c0; newVertexColors[vertexIndex + 1] = c0; newVertexColors[vertexIndex + 2] = c0; newVertexColors[vertexIndex + 3] = c0; } } //変形した頂点をTextMeshProに入れ for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; tmpText.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } //TextMeshProの色更新 tmpText.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); yield return(new WaitForSeconds(MoveUpdateInterval)); terminalTime += MoveUpdateInterval; if (terminalTime >= lifeCycle) { if (isLoop) { ResetVertics(); height = 0; terminalTime = 0; } } } onTerminal?.Invoke(); Destroy(gameObject); }
public IEnumerator TextJitter(int[] jitterIndices, float speedMultiplier) { List <TMP_WordInfo> wInfo; wInfo = new List <TMP_WordInfo>(); //Pre determine the vertexAnim variables for the text jitter effect //THIS MAY CAUSE LAG vertexAnim = null; vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } //Lag over while (true) { if (!cE.isColoring && !hasTextChanged) { dM.dialogueText.ForceMeshUpdate(true); } else { cE.ColorText(dM.mD.colorIndices.ToArray()); } wInfo.Clear(); foreach (int wordIndex in jitterIndices) { print("WORDINDEX: " + wordIndex); //Add each word's wordInfo wInfo.Add(dM.dialogueText.textInfo.wordInfo[wordIndex]); } Matrix4x4 matrix; int loopCount = 0; hasTextChanged = true; List <TMP_MeshInfo[]> cachedMeshInfo; cachedMeshInfo = new List <TMP_MeshInfo[]>(); cachedMeshInfo.Clear(); foreach (TMP_WordInfo wordInfo in wInfo) { cachedMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } if (hasTextChanged) { foreach (TMP_WordInfo wordInfo in wInfo) { cachedMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } hasTextChanged = false; } foreach (TMP_WordInfo info in wInfo) { foreach (TMP_MeshInfo[] cMI in cachedMeshInfo) { int characterCount = info.characterCount; if (characterCount == 0) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = 0; i < characterCount; i++) { int charIndex = info.firstCharacterIndex + i; TMP_CharacterInfo charInfo = dM.dialogueText.textInfo.characterInfo[charIndex]; if (!charInfo.isVisible) { continue; } VertexAnim vertAnim = vertexAnim[charIndex]; int materialIndex = dM.dialogueText.textInfo.characterInfo[charIndex].materialReferenceIndex; int vertexIndex = dM.dialogueText.textInfo.characterInfo[charIndex].vertexIndex; Vector3[] sourceVertices = cMI[materialIndex].vertices; Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; Vector3 offset = charMidBasline; Vector3[] destinationVertices = dM.dialogueText.textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } } } for (int i = 0; i < dM.dialogueText.textInfo.meshInfo.Length; i++) { dM.dialogueText.textInfo.meshInfo[i].mesh.vertices = dM.dialogueText.textInfo.meshInfo[i].vertices; dM.dialogueText.UpdateGeometry(dM.dialogueText.textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(speedMultiplier)); } }
IEnumerator AnimateVertexColors() { // We force an update of the text object since it would only be updated at the end of the frame. Ie. before this code is executed on the first frame. // Alternatively, we could yield and wait until the end of the frame when the text object will be generated. textMeshPro.ForceMeshUpdate(); TMP_TextInfo textInfo = textMeshPro.textInfo; Matrix4x4 matrix; int loopCount = 0; hasTextChanged = true; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. for (int i = 0; i < 1024; i++) { vertexAnim[i].damage = false; vertexAnim[i].offset = letterOffset; vertexAnim[i].alpha = 0; } // Cache the vertex data of the text object as the Jitter FX is applied to the original position of the characters. TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); characterCount = 1; Color32[] newVertexColors; for (int i = 0; i < textInfo.characterCount; i++) { int vertexIndex = textInfo.characterInfo[i].vertexIndex; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; Color32 colorAlpha = new Color32(255, 255, 255, 0); newVertexColors[vertexIndex + 0] = colorAlpha; newVertexColors[vertexIndex + 1] = colorAlpha; newVertexColors[vertexIndex + 2] = colorAlpha; newVertexColors[vertexIndex + 3] = colorAlpha; } while (true) { textMeshPro.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); // Get new copy of vertex data if the text has changed. if (hasTextChanged) { // Update the copy of the vertex data for the text object. cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); hasTextChanged = false; } actualTime += 1; if (actualTime == letterInterval && characterCount < textInfo.characterCount) { characterCount += 1; actualTime = 0; } if(characterCount == textInfo.characterCount) mouth.DesactivateMouth(); //int characterCount = textInfo.characterCount; // If No Characters then just yield and wait for some text to be added if (characterCount == 0) { yield return new WaitForSeconds(0.25f); continue; } // ======================================================= for (int i = 0; i < characterCount; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; // Skip characters that are not visible and thus have no geometry to manipulate. if (!charInfo.isVisible) continue; // Retrieve the pre-computed animation data for the given character. VertexAnim vertAnim = vertexAnim[i]; // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the cached vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; // Determine the center point of each character at the baseline. //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Determine the center point of each character. Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. // This is needed so the matrix TRS is applied at the origin for each character. Vector3 offset = charMidBasline; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; //vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); //Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); Vector3 position = new Vector3(0, vertAnim.offset, 0); matrix = Matrix4x4.TRS(position, Quaternion.identity, Vector3.one); vertAnim.offset *= letterCurveSpeed; destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; // ====================== Couleur ====================== // if (vertAnim.alpha != 255) { vertAnim.alpha += alphaSpeed; if (vertAnim.alpha > 255f) { vertAnim.alpha = 255f; } newVertexColors = textInfo.meshInfo[materialIndex].colors32; Color32 colorAlpha; if (vertexAnim[i].damage == true) colorAlpha = new Color32(damageColor.r, damageColor.g, damageColor.b, (byte)vertexAnim[i].alpha); else colorAlpha = new Color32(255, 255, 255, (byte)vertexAnim[i].alpha); newVertexColors[vertexIndex + 0] = colorAlpha; newVertexColors[vertexIndex + 1] = colorAlpha; newVertexColors[vertexIndex + 2] = colorAlpha; newVertexColors[vertexIndex + 3] = colorAlpha; } //textMeshPro.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); // ====================== Couleur ====================== // vertexAnim[i] = vertAnim; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; textMeshPro.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return null;//new WaitForSeconds(0.1f); } }
public IEnumerator ApplyEffects(string sentence, List <List <int> > colorIndices, int[] waveIndices, int[] jitterIndices) { int loopCount = 0; int lastLoopCount = 0; int currentCharTyping = 0; float lastTime = Time.time; List <TMP_WordInfo> jitterInfo; jitterInfo = new List <TMP_WordInfo>(); if (jitterIndices.Length > 0) { vertexAnim = null; vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } } List <TMP_WordInfo> waveInfo; waveInfo = new List <TMP_WordInfo>(); if (type) { dM.dialogueText.text = ""; yield return(new WaitUntil(() => dM.dB.isOpen)); dM.isTyping = true; dM.tdCheck = false; dM.dialogueText.text = sentence; dM.dialogueText.maxVisibleCharacters = sentence.ToCharArray().Length; dM.dialogueText.ForceMeshUpdate(true); ColorAllCharacters(0); } else { dM.dialogueText.text = sentence; } while (true) { if (type && currentCharTyping < sentence.ToCharArray().Length) { int waitCycles = 2; if (currentCharTyping > 0) { char lastCharTyped = sentence.ToCharArray()[currentCharTyping - 1]; char thisChar = sentence.ToCharArray()[currentCharTyping]; if (lastCharTyped != '.' || lastCharTyped != ',' || lastCharTyped != '?' || lastCharTyped != '!') { waitCycles = 2; if (sentence.ToCharArray()[currentCharTyping] == ' ') { currentCharTyping++; } } else { waitCycles = 5; } } if (lastLoopCount + waitCycles <= loopCount) { TMP_TextInfo typeInfo = dM.dialogueText.textInfo; Color32 typeColor = typeInfo.textComponent.color; typeColor.a = 255; for (int x = 0; x < colorIndices.Count; x++) { TMP_TextInfo colorDialogueInfo = dM.dialogueText.textInfo; if (colorIndices[x].Count != 0) { for (int y = 0; y < colorIndices[x].Count; y++) { TMP_WordInfo ColorWordInfo = colorDialogueInfo.wordInfo[colorIndices[x][y]]; for (int z = 0; z < ColorWordInfo.characterCount; z++) { if (currentCharTyping == ColorWordInfo.firstCharacterIndex + z) { typeColor = colors[x]; } } } } } int typeMeshIndex = dM.dialogueText.textInfo.characterInfo[currentCharTyping].materialReferenceIndex; int typeVertexIndex = dM.dialogueText.textInfo.characterInfo[currentCharTyping].vertexIndex; if (dM.dialogueText.text.ToCharArray()[currentCharTyping] == sentence.ToCharArray()[currentCharTyping]) { Color32[] typeVertexColors = dM.dialogueText.textInfo.meshInfo[typeMeshIndex].colors32; typeVertexColors[typeVertexIndex + 0] = typeColor; typeVertexColors[typeVertexIndex + 1] = typeColor; typeVertexColors[typeVertexIndex + 2] = typeColor; typeVertexColors[typeVertexIndex + 3] = typeColor; dM.dialogueText.UpdateVertexData(TMP_VertexDataUpdateFlags.All); } else { print("error"); } if (currentCharTyping < sentence.ToCharArray().Length) { currentCharTyping++; } lastLoopCount = loopCount; } } if (currentCharTyping >= sentence.ToCharArray().Length) { dM.isTyping = false; dM.tdCheck = true; type = false; currentCharTyping = 0; } if (!type) { for (int x = 0; x < colorIndices.Count; x++) { TMP_TextInfo colorDialogueInfo = dM.dialogueText.textInfo; if (colorIndices[x].Count != 0) { for (int y = 0; y < colorIndices[x].Count; y++) { TMP_WordInfo ColorWordInfo = colorDialogueInfo.wordInfo[colorIndices[x][y]]; for (int z = 0; z < ColorWordInfo.characterCount; z++) { int colorTypeMeshIndex = dM.dialogueText.textInfo.characterInfo[ColorWordInfo.firstCharacterIndex + z].materialReferenceIndex; int colorTypeVertexIndex = dM.dialogueText.textInfo.characterInfo[ColorWordInfo.firstCharacterIndex + z].vertexIndex; Color32[] colorTypeVertexColors = dM.dialogueText.textInfo.meshInfo[colorTypeMeshIndex].colors32; colorTypeVertexColors[colorTypeVertexIndex + 0] = colors[x]; colorTypeVertexColors[colorTypeVertexIndex + 1] = colors[x]; colorTypeVertexColors[colorTypeVertexIndex + 2] = colors[x]; colorTypeVertexColors[colorTypeVertexIndex + 3] = colors[x]; dM.dialogueText.UpdateVertexData(TMP_VertexDataUpdateFlags.All); } } } } if (dM.isTyping && !type) { dM.isTyping = false; dM.tdCheck = true; ColorAllCharacters(255); } } if (jitterIndices.Length > 0 && dM.dialogueText.textInfo.wordCount >= jitterIndices[0]) { jitterInfo.Clear(); foreach (int jitterIndex in jitterIndices) { jitterInfo.Add(dM.dialogueText.textInfo.wordInfo[jitterIndex]); } Matrix4x4 jitterMatrix; hasTextChanged = true; List <TMP_MeshInfo[]> cachedJitterMeshInfo; cachedJitterMeshInfo = new List <TMP_MeshInfo[]>(); foreach (TMP_WordInfo wordInfo in jitterInfo) { cachedJitterMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } if (hasTextChanged) { foreach (TMP_WordInfo wordInfo in jitterInfo) { cachedJitterMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } hasTextChanged = false; } foreach (TMP_WordInfo info in jitterInfo) { foreach (TMP_MeshInfo[] cMI in cachedJitterMeshInfo) { int jitterCharacterCount = info.characterCount; if (jitterCharacterCount == 0) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = 0; i < jitterCharacterCount; i++) { int jitterCharIndex = info.firstCharacterIndex + i; TMP_CharacterInfo jitterCharInfo = dM.dialogueText.textInfo.characterInfo[jitterCharIndex]; if (!jitterCharInfo.isVisible) { continue; } VertexAnim vertAnim = vertexAnim[jitterCharIndex]; int jitterMaterialIndex = dM.dialogueText.textInfo.characterInfo[jitterCharIndex].materialReferenceIndex; int jitterVertexIndex = dM.dialogueText.textInfo.characterInfo[jitterCharIndex].vertexIndex; Vector3[] jitterSourceVertices = cMI[jitterMaterialIndex].vertices; Vector2 jitterCharMidBasline = (jitterSourceVertices[jitterVertexIndex + 0] + jitterSourceVertices[jitterVertexIndex + 2]) / 2; Vector3 jitterOffset = jitterCharMidBasline; Vector3[] jitterDestinationVertices = dM.dialogueText.textInfo.meshInfo[jitterMaterialIndex].vertices; if (loopCount == 0) { SetInitialCoordinates(jitterCharIndex, jitterOffset); } jitterDestinationVertices[jitterVertexIndex + 0] = jitterSourceVertices[jitterVertexIndex + 0] - jitterOffset; jitterDestinationVertices[jitterVertexIndex + 1] = jitterSourceVertices[jitterVertexIndex + 1] - jitterOffset; jitterDestinationVertices[jitterVertexIndex + 2] = jitterSourceVertices[jitterVertexIndex + 2] - jitterOffset; jitterDestinationVertices[jitterVertexIndex + 3] = jitterSourceVertices[jitterVertexIndex + 3] - jitterOffset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterEffectOffset = new Vector3(Random.Range(-.5f, .5f), Random.Range(-.5f, .5f), 0); jitterMatrix = Matrix4x4.TRS(jitterEffectOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); jitterDestinationVertices[jitterVertexIndex + 0] = jitterMatrix.MultiplyPoint3x4(jitterDestinationVertices[jitterVertexIndex + 0]); jitterDestinationVertices[jitterVertexIndex + 1] = jitterMatrix.MultiplyPoint3x4(jitterDestinationVertices[jitterVertexIndex + 1]); jitterDestinationVertices[jitterVertexIndex + 2] = jitterMatrix.MultiplyPoint3x4(jitterDestinationVertices[jitterVertexIndex + 2]); jitterDestinationVertices[jitterVertexIndex + 3] = jitterMatrix.MultiplyPoint3x4(jitterDestinationVertices[jitterVertexIndex + 3]); jitterDestinationVertices[jitterVertexIndex + 0].y += initialYVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 1].y += initialYVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 2].y += initialYVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 3].y += initialYVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 0].x += initialXVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 1].x += initialXVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 2].x += initialXVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 3].x += initialXVal[jitterCharIndex]; jitterDestinationVertices[jitterVertexIndex + 0] += jitterEffectOffset; jitterDestinationVertices[jitterVertexIndex + 1] += jitterEffectOffset; jitterDestinationVertices[jitterVertexIndex + 2] += jitterEffectOffset; jitterDestinationVertices[jitterVertexIndex + 3] += jitterEffectOffset; vertexAnim[i] = vertAnim; } } } } if (waveIndices.Length > 0 && dM.dialogueText.textInfo.wordCount >= waveIndices[0]) { waveInfo.Clear(); foreach (int waveIndex in waveIndices) { //Add each word's wordInfo waveInfo.Add(dM.dialogueText.textInfo.wordInfo[waveIndex]); } Matrix4x4 waveMatrix; hasTextChanged = true; List <TMP_MeshInfo[]> cachedWaveMeshInfo; cachedWaveMeshInfo = new List <TMP_MeshInfo[]>(); cachedWaveMeshInfo.Clear(); foreach (TMP_WordInfo wordInfo in waveInfo) { cachedWaveMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } if (hasTextChanged) { foreach (TMP_WordInfo wordInfo in waveInfo) { cachedWaveMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } hasTextChanged = false; } foreach (TMP_WordInfo info in waveInfo) { int waveCharacterCount = info.characterCount; foreach (TMP_MeshInfo[] cMI in cachedWaveMeshInfo) { if (waveCharacterCount == 0) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = 0; i < waveCharacterCount; i++) { int waveCharIndex = info.firstCharacterIndex + i; TMP_CharacterInfo waveCharInfo = dM.dialogueText.textInfo.characterInfo[waveCharIndex]; if (!waveCharInfo.isVisible) { continue; } int waveMaterialIndex = dM.dialogueText.textInfo.characterInfo[waveCharIndex].materialReferenceIndex; int waveVertexIndex = dM.dialogueText.textInfo.characterInfo[waveCharIndex].vertexIndex; Vector3[] waveSourceVertices = cMI[waveMaterialIndex].vertices; Vector2 waveCharMidBasline = (waveSourceVertices[waveVertexIndex + 0] + waveSourceVertices[waveVertexIndex + 2]) / 2; Vector3 waveOffset = waveCharMidBasline; Vector3[] waveDestinationVertices = dM.dialogueText.textInfo.meshInfo[waveMaterialIndex].vertices; if (loopCount == 0) { SetInitialCoordinates(waveCharIndex, waveOffset); } waveDestinationVertices[waveVertexIndex + 0] = waveSourceVertices[waveVertexIndex + 0] - waveOffset; waveDestinationVertices[waveVertexIndex + 1] = waveSourceVertices[waveVertexIndex + 1] - waveOffset; waveDestinationVertices[waveVertexIndex + 2] = waveSourceVertices[waveVertexIndex + 2] - waveOffset; waveDestinationVertices[waveVertexIndex + 3] = waveSourceVertices[waveVertexIndex + 3] - waveOffset; Vector3 waveEffectOffset = new Vector3(0, Mathf.Cos((waveCharIndex * waveFrequency) - Time.time * 6) * 2, 0); waveMatrix = Matrix4x4.TRS(waveEffectOffset, Quaternion.Euler(0, 0, 0), Vector3.one); waveDestinationVertices[waveVertexIndex + 0] = waveMatrix.MultiplyPoint3x4(waveDestinationVertices[waveVertexIndex + 0]); waveDestinationVertices[waveVertexIndex + 1] = waveMatrix.MultiplyPoint3x4(waveDestinationVertices[waveVertexIndex + 1]); waveDestinationVertices[waveVertexIndex + 2] = waveMatrix.MultiplyPoint3x4(waveDestinationVertices[waveVertexIndex + 2]); waveDestinationVertices[waveVertexIndex + 3] = waveMatrix.MultiplyPoint3x4(waveDestinationVertices[waveVertexIndex + 3]); waveDestinationVertices[waveVertexIndex + 0].y += waveEffectOffset.y; waveDestinationVertices[waveVertexIndex + 1].y += waveEffectOffset.y; waveDestinationVertices[waveVertexIndex + 2].y += waveEffectOffset.y; waveDestinationVertices[waveVertexIndex + 3].y += waveEffectOffset.y; waveDestinationVertices[waveVertexIndex + 0].y += initialYVal[waveCharIndex]; waveDestinationVertices[waveVertexIndex + 1].y += initialYVal[waveCharIndex]; waveDestinationVertices[waveVertexIndex + 2].y += initialYVal[waveCharIndex]; waveDestinationVertices[waveVertexIndex + 3].y += initialYVal[waveCharIndex]; waveDestinationVertices[waveVertexIndex + 0].x += waveOffset.x; waveDestinationVertices[waveVertexIndex + 1].x += waveOffset.x; waveDestinationVertices[waveVertexIndex + 2].x += waveOffset.x; waveDestinationVertices[waveVertexIndex + 3].x += waveOffset.x; } } } } for (int i = 0; i < dM.dialogueText.textInfo.meshInfo.Length; i++) { dM.dialogueText.textInfo.meshInfo[i].mesh.vertices = dM.dialogueText.textInfo.meshInfo[i].vertices; dM.dialogueText.UpdateGeometry(dM.dialogueText.textInfo.meshInfo[i].mesh, i); } loopCount += 1; lastTime = Time.time; yield return(new WaitForSecondsRealtime(0.01f)); } }
IEnumerator AnimateVertex() { textComponent.ForceMeshUpdate(); var textInfo = textComponent.textInfo; Matrix4x4 matrix; int loopCount = 0; hasTextChanged = true; VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); while (true) { if (hasTextChanged) { cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); hasTextChanged = false; } int characterCount = textInfo.characterCount; for (int i = 0; i < characterCount; i++) { var charInfo = textInfo.characterInfo[i]; if (!charInfo.isVisible) { continue; } VertexAnim vertAnim = vertexAnim[i]; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; int vertexIndex = textInfo.characterInfo[i].vertexIndex; Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; Vector2 charMidBaseLine = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; Vector3 offset = charMidBaseLine; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep( -vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 wobblingOffset = new Vector3( Random.Range(-0.25f, 0.25f), Random.Range(-0.25f, 0.25f), 0); matrix = Matrix4x4.TRS( wobblingOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; textComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(1f * SpeedMultiplier)); } }
private IEnumerator ShakeText(int startIndex, int endIndex) { textBoxDialogue.ForceMeshUpdate(); textChanged = true; TMP_TextInfo textInfo = textBoxDialogue.textInfo; Matrix4x4 matrix; int loopCount = 0; VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); while (true) { if (textChanged) { cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); textChanged = false; } int charCount = textInfo.characterCount; if (charCount == 0) { yield return(new WaitForSeconds(typewriterTime)); continue; } for (int i = startIndex; i < endIndex; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; if (!charInfo.isVisible) { continue; } VertexAnim vertAnim = vertexAnim[i]; // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the cached vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; // Determine the center point of each character at the baseline. //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Determine the center point of each character. Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. // This is needed so the matrix TRS is applied at the origin for each character. Vector3 offset = charMidBasline; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; textBoxDialogue.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(0.1f)); yield return(new WaitForEndOfFrame()); } }
/// <summary> /// Method to animate vertex colors of a TMP Text object. /// </summary> /// <returns></returns> IEnumerator AnimateVertexColors() { // We force an update of the text object since it would only be updated at the end of the frame. Ie. before this code is executed on the first frame. // Alternatively, we could yield and wait until the end of the frame when the text object will be generated. m_TextComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = m_TextComponent.textInfo; Matrix4x4 matrix; Vector3[][] copyOfVertices = new Vector3[0][]; int loopCount = 0; hasTextChanged = true; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } while (true) { // Allocate new vertices 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; } int characterCount = textInfo.characterCount; // If No Characters then just yield and wait for some text to be added if (characterCount == 0) { yield return new WaitForSeconds(0.25f); continue; } for (int i = 0; i < characterCount; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; // Skip characters that are not visible and thus have no geometry to manipulate. if (!charInfo.isVisible) continue; // Retrieve the pre-computed animation data for the given character. VertexAnim vertAnim = vertexAnim[i]; // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = textInfo.meshInfo[materialIndex].vertices; // Determine the center point of each character at the baseline. //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. // This is needed so the matrix TRS is applied at the origin for each character. Vector3 offset = charMidBasline; copyOfVertices[materialIndex][vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; copyOfVertices[materialIndex][vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; copyOfVertices[materialIndex][vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; copyOfVertices[materialIndex][vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); copyOfVertices[materialIndex][vertexIndex + 0] = matrix.MultiplyPoint3x4(copyOfVertices[materialIndex][vertexIndex + 0]); copyOfVertices[materialIndex][vertexIndex + 1] = matrix.MultiplyPoint3x4(copyOfVertices[materialIndex][vertexIndex + 1]); copyOfVertices[materialIndex][vertexIndex + 2] = matrix.MultiplyPoint3x4(copyOfVertices[materialIndex][vertexIndex + 2]); copyOfVertices[materialIndex][vertexIndex + 3] = matrix.MultiplyPoint3x4(copyOfVertices[materialIndex][vertexIndex + 3]); copyOfVertices[materialIndex][vertexIndex + 0] += offset; copyOfVertices[materialIndex][vertexIndex + 1] += offset; copyOfVertices[materialIndex][vertexIndex + 2] += offset; copyOfVertices[materialIndex][vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = copyOfVertices[i]; m_TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return new WaitForSeconds(0.1f); } }
IEnumerator TextJitter() { List <TMP_WordInfo> wInfo; wInfo = new List <TMP_WordInfo>(); int[] wordsToJitter; wordsToJitter = null; if (jitterWords != null) { wordsToJitter = jitterWords.ToArray(); } else { wordsToJitter = textFX[sentenceCount].jitterIndexes; } while (true) { if (sentenceCount < textFX.Length) { if (textFX[sentenceCount].wordColors.keyWords.Length != 0) { SetTextColor(keyColor, textFX[sentenceCount].wordColors.keyWords); } else if (textFX[sentenceCount].wordColors.characterWords.Length != 0) { SetTextColor(characterColor, textFX[sentenceCount].wordColors.characterWords); } else if (textFX[sentenceCount].wordColors.redWords.Length != 0) { SetTextColor(redColor, textFX[sentenceCount].wordColors.redWords); } else if (textFX[sentenceCount].wordColors.mechanicWords.Length != 0) { SetTextColor(mechanicColor, textFX[sentenceCount].wordColors.mechanicWords); } else { dialogueText.ForceMeshUpdate(true); } } wInfo.Clear(); foreach (int wordIndex in wordsToJitter) { //Add each word's wordInfo wInfo.Add(dialogueText.textInfo.wordInfo[wordIndex]); } Matrix4x4 matrix; int loopCount = 0; hasTextChanged = true; List <TMP_MeshInfo[]> cachedMeshInfo; cachedMeshInfo = new List <TMP_MeshInfo[]>(); cachedMeshInfo.Clear(); foreach (TMP_WordInfo wordInfo in wInfo) { cachedMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } if (hasTextChanged) { foreach (TMP_WordInfo wordInfo in wInfo) { cachedMeshInfo.Add(wordInfo.textComponent.textInfo.CopyMeshInfoVertexData()); } hasTextChanged = false; } foreach (TMP_WordInfo info in wInfo) { foreach (TMP_MeshInfo[] cMI in cachedMeshInfo) { int characterCount = info.characterCount; if (characterCount == 0) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = 0; i < characterCount; i++) { int charIndex = info.firstCharacterIndex + i; TMP_CharacterInfo charInfo = dialogueText.textInfo.characterInfo[charIndex]; if (!charInfo.isVisible) { continue; } VertexAnim vertAnim = vertexAnim[charIndex]; int materialIndex = dialogueText.textInfo.characterInfo[charIndex].materialReferenceIndex; int vertexIndex = dialogueText.textInfo.characterInfo[charIndex].vertexIndex; Vector3[] sourceVertices = cMI[materialIndex].vertices; Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; Vector3 offset = charMidBasline; Vector3[] destinationVertices = dialogueText.textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * CurveScale, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * AngleMultiplier), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } } } for (int i = 0; i < dialogueText.textInfo.meshInfo.Length; i++) { dialogueText.textInfo.meshInfo[i].mesh.vertices = dialogueText.textInfo.meshInfo[i].vertices; dialogueText.UpdateGeometry(dialogueText.textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(0.1f)); } }
//Jitters the part of the text public IEnumerator Jitter(RPGTalkJitter jitter) { #if RPGTalk_TMP if (TMPText == null) { Debug.LogError("Only TextMeshPro users can use the Jitter Tag"); yield return(null); } TMP_TextInfo textInfo = TMPText.textInfo; // Cache the vertex data of the text object as the Jitter FX is applied to the original position of the characters. TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); int characterCount = textInfo.characterCount; // Create an Array which contains pre-computed Angle Ranges and Speeds for a bunch of characters. VertexAnim[] vertexAnim = new VertexAnim[1024]; for (int i = 0; i < 1024; i++) { vertexAnim[i].angleRange = Random.Range(10f, 25f); vertexAnim[i].speed = Random.Range(1f, 3f); } int loopCount = 0; Matrix4x4 matrix; while (true) { int repeatUntil = jitter.jitterPosition + jitter.numberOfCharacters; // yield until we have all the characters in the jitter while (characterCount < repeatUntil) { // Update the copy of the vertex data for the text object. cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); characterCount = textInfo.characterCount; yield return(new WaitForEndOfFrame()); continue; } for (int i = jitter.jitterPosition; i < repeatUntil; i++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[i]; // Skip characters that are not visible and thus have no geometry to manipulate. if (!charInfo.isVisible) { continue; } // Retrieve the pre-computed animation data for the given character. VertexAnim vertAnim = vertexAnim[i]; // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the cached vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; // If we dont have the vertices yet, don't do it if (sourceVertices.Length < vertexIndex + 3) { continue; } // Determine the center point of each character at the baseline. //Vector2 charMidBasline = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); // Determine the center point of each character. Vector2 charMidBasline = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; // Need to translate all 4 vertices of each quad to aligned with middle of character / baseline. // This is needed so the matrix TRS is applied at the origin for each character. Vector3 offset = charMidBasline; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; destinationVertices[vertexIndex + 0] = sourceVertices[vertexIndex + 0] - offset; destinationVertices[vertexIndex + 1] = sourceVertices[vertexIndex + 1] - offset; destinationVertices[vertexIndex + 2] = sourceVertices[vertexIndex + 2] - offset; destinationVertices[vertexIndex + 3] = sourceVertices[vertexIndex + 3] - offset; vertAnim.angle = Mathf.SmoothStep(-vertAnim.angleRange, vertAnim.angleRange, Mathf.PingPong(loopCount / 25f * vertAnim.speed, 1f)); Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); matrix = Matrix4x4.TRS(jitterOffset * jitter.jitter, Quaternion.Euler(0, 0, Random.Range(-5f, 5f) * jitter.angle), Vector3.one); destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]); destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]); destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]); destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]); destinationVertices[vertexIndex + 0] += offset; destinationVertices[vertexIndex + 1] += offset; destinationVertices[vertexIndex + 2] += offset; destinationVertices[vertexIndex + 3] += offset; vertexAnim[i] = vertAnim; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; TMPText.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(0.1f)); } #else Debug.LogError("Only TextMeshPro users can use the Jitter Tag"); yield return(null); #endif }