private IEnumerator AnimateText(string actor, string text) { isAnimatingText = true; TMP_Text dialogueBox = textMeshPro.GetComponent <TextMeshProUGUI>(); dialogueBox.text = StripAllCommands(text); dialogueBox.ForceMeshUpdate(); dialogueBox.fontSize = FontSize; dialogueBox.alignment = TextAlignmentOptions.TopJustified; specialCommands = BuildSpecialCommandList(text); //Count how many characters we have in our new dialogue line. TMP_TextInfo textInfo = dialogueBox.textInfo; int totalCharacters = dialogueBox.textInfo.characterCount; LoadImage(actor); //Base color for our text. Color32 c0 = dialogueBox.color; //Shake text if true. if (isTextShaking) { StartCoroutine(ShakingText(dialogueBox)); } //We now hide text based on each character's alpha value HideText(dialogueBox); var i = 0; while (i < totalCharacters) { //If we change the text live on runtime in our inspector, adjust the character count! if (hasTextChanged) { totalCharacters = textInfo.characterCount; // Update visible character count. hasTextChanged = false; } if (specialCommands.Count > 0) { CheckForCommands(i, dialogueBox); } //Instead of incrementing maxVisibleCharacters or add the current character to our string, we do this : // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the vertex colors of the mesh used by this text element (character or sprite). //Color of all characters' vertices. var newVertexColors = textInfo.meshInfo[materialIndex].colors32; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Only change the vertex color if the text element is visible. (It's visible, only the alpha color is 0) if (textInfo.characterInfo[i].isVisible && isColorizing == false) { UpdateVertexColors(newVertexColors, vertexIndex, c0, dialogueBox); } else if (textInfo.characterInfo[i].isVisible && isColorizing == true) { UpdateVertexColors(newVertexColors, vertexIndex, c1, dialogueBox); } i++; if (!skip) { yield return(new WaitForSeconds(SpeedText)); } } Debug.Log("Done animating!"); isAnimatingText = false; yield return(null); }
public override void SetQuestion(Question q, UnityAction <Question> answeredEvent, UISkinData skinData) { base.SetQuestion(q, answeredEvent, skinData); radioListQuestion = question as RadioListQuestion; instructionsText.text = question.instructions; idText.text = question.id; toggles = new List <Toggle>(); //VariableGridLayoutGroup gridLayout; //LayoutGroup layoutGroup; //if(radioListQuestion.horizontal) { // layoutGroup = itemsUI.gameObject.AddComponent<HorizontalLayoutGroup>(); // layoutGroup.childAlignment = TextAnchor.MiddleCenter; // layoutGroup.padding.left = 1; // layoutGroup.padding.right = 1; // layoutGroup.padding.top = 1; // layoutGroup.padding.bottom = 1; //} else { // layoutGroup = itemsUI.gameObject.AddComponent<VerticalLayoutGroup>(); // layoutGroup.childAlignment = TextAnchor.MiddleCenter; // layoutGroup.padding.left = 1; // layoutGroup.padding.right = 1; // layoutGroup.padding.top = 1; // layoutGroup.padding.bottom = 1; //} VariableGridLayoutGroup gridLayoutGroup = itemsUI.gameObject.AddComponent <VariableGridLayoutGroup>(); gridLayoutGroup.childAlignment = TextAnchor.MiddleCenter; gridLayoutGroup.padding.left = 1; gridLayoutGroup.padding.right = 1; gridLayoutGroup.padding.top = 1; gridLayoutGroup.padding.bottom = 1; gridLayoutGroup.spacing = new Vector2(0, skinData.fontSizeBody); gridLayoutGroup.constraint = VariableGridLayoutGroup.Constraint.FixedColumnCount; gridLayoutGroup.constraintCount = 2; for (int i = 0; i < radioListQuestion.labels.Length; i++) { //GameObject container = new GameObject("container",typeof(RectTransform)); //container.AddComponent<HorizontalLayoutGroup>(); GameObject label = Instantiate(labelPrefab); LayoutElement labelLayout = label.GetComponent <LayoutElement>(); labelLayout.flexibleWidth = skinData.canvasSize.x * 0.6f; // 10; labelLayout.preferredWidth = skinData.canvasSize.x * 0.75f; labelLayout.minWidth = -1; labelLayout.minHeight = -1; //labelLayout.flexibleWidth = 10; //labelLayout.preferredWidth = 12; //labelLayout.minWidth = -1; //labelLayout.minHeight = -1; TMP_Text text = label.GetComponent <TMP_Text>(); text.text = radioListQuestion.labels[i]; //text.autoSizeTextContainer = true; //text.enableAutoSizing = true; text.ForceMeshUpdate(true); text.GetComponent <SkinText>().textFormat = TextFormat.Body; text.margin = new Vector4(text.fontSize, 0, 0, 0); GameObject radioItem = Instantiate(radioItemPrefab); Toggle toggle = radioItem.GetComponent <Toggle>(); LayoutElement toggleLayout = toggle.GetComponent <LayoutElement>(); toggleLayout.flexibleWidth = 1; toggle.SetIsOnWithoutNotify(false); toggles.Add(toggle); toggle.onValueChanged.AddListener((val) => { OnItemSelected(toggle, radioListQuestion.id, val); }); //container.transform.parent = itemsUI; radioItem.transform.parent = itemsUI; label.transform.parent = itemsUI; //container.transform.localPosition = Vector3.zero; //container.transform.localRotation = Quaternion.identity; //container.transform.localScale = Vector3.one; label.transform.localPosition = Vector3.zero; label.transform.localRotation = Quaternion.identity; label.transform.localScale = Vector3.one; // label.transform.parent.localScale; radioItem.transform.localPosition = Vector3.zero; radioItem.transform.localRotation = Quaternion.identity; radioItem.transform.localScale = Vector3.one; // radioItem.transform.parent.localScale; if (label.GetComponent <Button>()) { Button btn = label.GetComponent <Button>(); btn.onClick.AddListener(() => { toggle.isOn = !toggle.isOn; }); } } LayoutRebuilder.ForceRebuildLayoutImmediate(itemsUI); //Canvas.ForceUpdateCanvases(); }
/// <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. _mTextComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = _mTextComponent.textInfo; Matrix4x4 matrix; Vector3[][] copyOfVertices = new Vector3[0][]; _hasTextChanged = true; 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; } int lineCount = textInfo.lineCount; // Iterate through each line of the text. for (int i = 0; i < lineCount; i++) { int first = textInfo.lineInfo[i].firstCharacterIndex; int last = textInfo.lineInfo[i].lastCharacterIndex; // Determine the center of each line Vector3 centerOfLine = (textInfo.characterInfo[first].bottomLeft + textInfo.characterInfo[last].topRight) / 2; Quaternion rotation = Quaternion.Euler(0, 0, Random.Range(-0.25f, 0.25f) * rotationMultiplier); // Iterate through each character of the line. for (int j = first; j <= last; j++) { // Skip characters that are not visible and thus have no geometry to manipulate. if (!textInfo.characterInfo[j].isVisible) { continue; } // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[j].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[j].vertexIndex; // Get the vertices of the mesh used by this text element (character or sprite). Vector3[] sourceVertices = textInfo.meshInfo[materialIndex].vertices; // Need to translate all 4 vertices of each quad to aligned with center of character. // This is needed so the matrix TRS is applied at the origin for each character. copyOfVertices[materialIndex][vertexIndex + 0] = sourceVertices[vertexIndex + 0] - centerOfLine; copyOfVertices[materialIndex][vertexIndex + 1] = sourceVertices[vertexIndex + 1] - centerOfLine; copyOfVertices[materialIndex][vertexIndex + 2] = sourceVertices[vertexIndex + 2] - centerOfLine; copyOfVertices[materialIndex][vertexIndex + 3] = sourceVertices[vertexIndex + 3] - centerOfLine; // Determine the random scale change for each character. float randomScale = Random.Range(0.995f - 0.001f * scaleMultiplier, 1.005f + 0.001f * scaleMultiplier); // Setup the matrix rotation. matrix = Matrix4x4.TRS(Vector3.one, rotation, Vector3.one * randomScale); // Apply the matrix TRS to the individual characters relative to the center of the current line. 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]); // Revert the translation change. copyOfVertices[materialIndex][vertexIndex + 0] += centerOfLine; copyOfVertices[materialIndex][vertexIndex + 1] += centerOfLine; copyOfVertices[materialIndex][vertexIndex + 2] += centerOfLine; copyOfVertices[materialIndex][vertexIndex + 3] += centerOfLine; } } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { textInfo.meshInfo[i].mesh.vertices = copyOfVertices[i]; _mTextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } yield return(new WaitForSeconds(0.1f)); } }
IEnumerator RevealText() { m_TextComponent.ForceMeshUpdate(); if (runningEffect != null) { StopCoroutine(runningEffect); } runningEffect = AnimateVertexColors(); StartCoroutine(runningEffect); TMP_TextInfo textInfo = m_TextComponent.textInfo; int numCharacters = textInfo.characterCount; Color32[] newVertexColors; // Turn everything invisible for (int i = 0; i < numCharacters; i++) { int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Set new alpha values. newVertexColors[vertexIndex + 0].a = 0; newVertexColors[vertexIndex + 1].a = 0; newVertexColors[vertexIndex + 2].a = 0; newVertexColors[vertexIndex + 3].a = 0; } m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); for (int i = 0; i < numCharacters; i++) { if (disabled || finished) { break; } if (!textInfo.characterInfo[i].isVisible) { continue; } int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Set new alpha values. newVertexColors[vertexIndex + 0].a = 255; newVertexColors[vertexIndex + 1].a = 255; newVertexColors[vertexIndex + 2].a = 255; newVertexColors[vertexIndex + 3].a = 255; m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); yield return(new WaitForSecondsRealtime(0.03f / speedMultiplier)); } finished = true; dialogueHUD.OnDialogueRevealEnd(); }
/// <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; TMP_MeshInfo[] cachedMeshInfoVertexData = textInfo.CopyMeshInfoVertexData(); // Allocations for sorting of the modified scales List <float> modifiedCharScale = new List <float>(); List <int> scaleSortingOrder = new List <int>(); hasTextChanged = true; while (true) { // Allocate new vertices if (hasTextChanged) { // Get updated vertex data cachedMeshInfoVertexData = textInfo.CopyMeshInfoVertexData(); 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; } // Clear list of character scales modifiedCharScale.Clear(); scaleSortingOrder.Clear(); 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; } // 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 = cachedMeshInfoVertexData[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; //Vector3 jitterOffset = new Vector3(Random.Range(-.25f, .25f), Random.Range(-.25f, .25f), 0); // Determine the random scale change for each character. float randomScale = Random.Range(1f, 1.5f); // Add modified scale and index modifiedCharScale.Add(randomScale); scaleSortingOrder.Add(modifiedCharScale.Count - 1); // Setup the matrix for the scale change. //matrix = Matrix4x4.TRS(jitterOffset, Quaternion.Euler(0, 0, Random.Range(-5f, 5f)), Vector3.one * randomScale); matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, Vector3.one * randomScale); 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; // Restore Source UVS which have been modified by the sorting Vector2[] sourceUVs0 = cachedMeshInfoVertexData[materialIndex].uvs0; Vector2[] destinationUVs0 = textInfo.meshInfo[materialIndex].uvs0; destinationUVs0[vertexIndex + 0] = sourceUVs0[vertexIndex + 0]; destinationUVs0[vertexIndex + 1] = sourceUVs0[vertexIndex + 1]; destinationUVs0[vertexIndex + 2] = sourceUVs0[vertexIndex + 2]; destinationUVs0[vertexIndex + 3] = sourceUVs0[vertexIndex + 3]; // Restore Source Vertex Colors Color32[] sourceColors32 = cachedMeshInfoVertexData[materialIndex].colors32; Color32[] destinationColors32 = textInfo.meshInfo[materialIndex].colors32; destinationColors32[vertexIndex + 0] = sourceColors32[vertexIndex + 0]; destinationColors32[vertexIndex + 1] = sourceColors32[vertexIndex + 1]; destinationColors32[vertexIndex + 2] = sourceColors32[vertexIndex + 2]; destinationColors32[vertexIndex + 3] = sourceColors32[vertexIndex + 3]; } // Push changes into meshes for (int i = 0; i < textInfo.meshInfo.Length; i++) { //// Sort Quads based modified scale scaleSortingOrder.Sort((a, b) => modifiedCharScale[a].CompareTo(modifiedCharScale[b])); textInfo.meshInfo[i].SortGeometry(scaleSortingOrder); // Updated modified vertex attributes textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices; textInfo.meshInfo[i].mesh.uv = textInfo.meshInfo[i].uvs0; textInfo.meshInfo[i].mesh.colors32 = textInfo.meshInfo[i].colors32; m_TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } yield return(new WaitForSeconds(0.1f)); } }
public void onTextStarted() { textField.ForceMeshUpdate(); //Vector2 preferredWidth = textField.GetPreferredValues(textField.text,); Resize(textField.renderedWidth, textField.renderedHeight); }
/// <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; int loopCount = 0; hasTextChanged = true; // 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 == 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; } // 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; float angle = Mathf.Sin(Time.time * 10 + i * 0.8f) * 5; float x = Mathf.Sin(Time.time * 8 + i * 0.8f) * ScaleX; float y = Mathf.Sin(Time.time * 11 + i * 0.8f) * ScaleY; Vector3 jitterOffset = new Vector3(x, y, 0); matrix = Matrix4x4.TRS(jitterOffset, Quaternion.Euler(0, 0, angle * 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; } // Push changes into meshes 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); } loopCount += 1; yield return(null); // yield return new WaitForSeconds(0.1f); } }
IEnumerator AnimateVertexColors() { // Force the text object to update right away so we can have geometry to modify right from the start. m_TextComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = m_TextComponent.textInfo; Color32[] newVertexColors; Color32 c0 = m_TextComponent.color; int currentCharacterWave = 0; while (true) { 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; } if (!active) { for (int currentCharacter = 0; currentCharacter < characterCount; currentCharacter++) { int materialIndex = textInfo.characterInfo[currentCharacter].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[currentCharacter].vertexIndex; if (!textInfo.characterInfo[currentCharacter].isVisible) { continue; } int r = 255; int g = 255; int b = 255; int a = 255; c0 = new Color32((byte)r, (byte)g, (byte)b, (byte)a); newVertexColors[vertexIndex + 0] = c0; newVertexColors[vertexIndex + 1] = c0; newVertexColors[vertexIndex + 2] = c0; newVertexColors[vertexIndex + 3] = c0; m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); } } else { int materialIndex = textInfo.characterInfo[currentCharacterWave].materialReferenceIndex; newVertexColors = textInfo.meshInfo[materialIndex].colors32; int vertexIndex = textInfo.characterInfo[currentCharacterWave].vertexIndex; if (textInfo.characterInfo[currentCharacterWave].isVisible) { int r = (int)((Mathf.Sin(Time.time) + 1) / 2 * 255 / 2); int g = (int)((Mathf.Cos(Time.time) + 1) / 2 * 255 / 2); int b = 255; int a = 255; c0 = new Color32((byte)r, (byte)g, (byte)b, (byte)a); newVertexColors[vertexIndex + 0] = c0; newVertexColors[vertexIndex + 1] = c0; newVertexColors[vertexIndex + 2] = c0; newVertexColors[vertexIndex + 3] = c0; // New function which pushes (all) updated vertex data to the appropriate meshes when using either the Mesh Renderer or CanvasRenderer. m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); // This last process could be done to only update the vertex data that has changed as opposed to all of the vertex data but it would require extra steps and knowing what type of renderer is used. // These extra steps would be a performance optimization but it is unlikely that such optimization will be necessary. } currentCharacterWave = (currentCharacterWave + 1) % characterCount; } yield return(new WaitForSeconds(0.005f)); } }
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); } }
IEnumerator Showing() { tmpTextObject.ForceMeshUpdate(); //Taken from a text mesh pro example TMP_TextInfo textInfo = tmpTextObject.textInfo; Color32[] newVertexColors; int currentCharacter = 0; int startingCharacterRange = currentCharacter; bool isRangeMax = false; while (!isRangeMax) { int characterCount = textInfo.characterCount; // Spread should not exceed the number of characters. byte fadeSteps = (byte)Mathf.Max(1, 255 / textSpeed); for (int i = startingCharacterRange; i < currentCharacter + 1; i++) { // Skip characters that are not visible if (!textInfo.characterInfo[i].isVisible) { continue; } // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the vertex colors of the mesh used by this text element (character or sprite). newVertexColors = textInfo.meshInfo[materialIndex].colors32; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the current character's alpha value. byte alpha = (byte)Mathf.Clamp(newVertexColors[vertexIndex + 0].a + fadeSteps, 0, 255); // Set new alpha values. newVertexColors[vertexIndex + 0].a = alpha; newVertexColors[vertexIndex + 1].a = alpha; newVertexColors[vertexIndex + 2].a = alpha; newVertexColors[vertexIndex + 3].a = alpha; if (alpha == 0) { startingCharacterRange += 1; if (startingCharacterRange == characterCount) { // Update mesh vertex data one last time. tmpTextObject.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); yield return(new WaitForSeconds(1.0f)); // Reset the text object back to original state. tmpTextObject.ForceMeshUpdate(); yield return(new WaitForSeconds(1.0f)); // Reset our counters. currentCharacter = 0; startingCharacterRange = 0; //isRangeMax = true; // Would end the coroutine. } } } // Upload the changed vertex colors to the Mesh. tmpTextObject.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); if (currentCharacter + 1 < characterCount) { currentCharacter += 1; } yield return(new WaitForSeconds(0.25f - fadeSpeed * 0.01f)); } }
/// <summary> /// Method to curve text along a Unity animation curve. /// </summary> /// <param name="textComponent"></param> /// <returns></returns> IEnumerator WarpText() { //HERE IS THE LINE THAT F***S EVERYTHING UP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // VertexCurve.preWrapMode = WrapMode.Loop; // VertexCurve.postWrapMode = WrapMode.Loop; //Mesh mesh = m_TextComponent.textInfo.meshInfo[0].mesh; Vector3[] vertices; Matrix4x4 matrix; m_TextComponent.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated. // CurveScale *= 10; //float old_CurveScale = CurveScale; //AnimationCurve old_curve = CopyAnimationCurve(VertexCurve); float _time = 0; while (true) { /* * if (!m_TextComponent.havePropertiesChanged && old_CurveScale == CurveScale && old_curve.keys[1].value == VertexCurve.keys[1].value) * { * yield return null; * continue; * } */ //old_CurveScale = CurveScale; //old_curve = CopyAnimationCurve(VertexCurve); //m_TextComponent.color = color; m_TextComponent.ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate. TMP_TextInfo textInfo = m_TextComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount == 0) { continue; } //vertices = textInfo.meshInfo[0].vertices; //int lastVertexIndex = textInfo.characterInfo[characterCount - 1].vertexIndex; float boundsMinX = m_TextComponent.bounds.min.x; //textInfo.meshInfo[0].mesh.bounds.min.x; float boundsMaxX = m_TextComponent.bounds.max.x; //textInfo.meshInfo[0].mesh.bounds.max.x; for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the index of the mesh used by this character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; // Compute the baseline mid point for each character Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //float offsetY = VertexCurve.Evaluate((float)i / characterCount + loopCount / 50f); // Random.Range(-0.25f, 0.25f); // Apply offset to adjust our pivot point. vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; // Compute the angle of rotation for each character based on the animation curve float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. float x1 = x0 + 0.0001f; float y0 = VertexCurve.Evaluate(x0 + _time * SpeedMultiplier) * CurveScale; float y1 = VertexCurve.Evaluate(x1 + _time * SpeedMultiplier) * CurveScale; Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - offsetToMidBaseline.x, 0); Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) - new Vector3(offsetToMidBaseline.x, y0); float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; Vector3 cross = Vector3.Cross(horizontal, tangent); float angle = cross.z > 0 ? dot : 360 - dot; matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), 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] += offsetToMidBaseline; vertices[vertexIndex + 1] += offsetToMidBaseline; vertices[vertexIndex + 2] += offsetToMidBaseline; vertices[vertexIndex + 3] += offsetToMidBaseline; } // Upload the mesh with the revised information m_TextComponent.UpdateVertexData(); yield return(new WaitForSecondsRealtime(0.025f)); _time += 0.025f; } }
void UpdateCurveMesh() { textComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = textComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount == 0) { return; } Vector3 baseline = new Vector3(); Vector3 prevAngleDirection = new Vector3(); Vector3 prevOffsetToMidBaseline = new Vector3(); Vector3[] vertices; Matrix4x4 matrix; float defaultBaseLine = 0; float maxBaseLine = float.MinValue; float minBaseLine = float.MaxValue; bool isFirst = true; for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } int vertexIndex = textInfo.characterInfo[i].vertexIndex; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; //文字の真ん中の点と文字の基準となるベースラインの高さを取得 Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //文字の中央の下が原点となるように頂点を移動(これから回転と移動をさせるため) vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; //曲線の傾き(agnle)の計算 float x0 = (float)(i + 1) / (characterCount + 1); float x1 = x0 + 0.0001f; float y0 = vertexCurve.Evaluate(x0); float y1 = vertexCurve.Evaluate(x1); Vector3 horizontal = new Vector3(1, 0, 0); Vector3 tangent = new Vector3(0.0001f, (y1 - y0)); Vector3 angleDirection = tangent.normalized; float angle = Mathf.Acos(Vector3.Dot(horizontal, angleDirection)) * Mathf.Rad2Deg; Vector3 cross = Vector3.Cross(horizontal, tangent); angle = cross.z > 0 ? angle : 360 - angle; //angle回転させた頂点位置の計算 matrix = Matrix4x4.Rotate(Quaternion.Euler(0, 0, angle)); 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]); //文字間の計算 float characterSpace; if (isFirst) { baseline = offsetToMidBaseline; defaultBaseLine = baseline.y; characterSpace = 0; isFirst = false; } else { characterSpace = (offsetToMidBaseline - prevOffsetToMidBaseline).magnitude; } prevOffsetToMidBaseline = offsetToMidBaseline; //文字位置を計算して移動 baseline = baseline + (angleDirection + prevAngleDirection).normalized * characterSpace; vertices[vertexIndex + 0] += baseline; vertices[vertexIndex + 1] += baseline; vertices[vertexIndex + 2] += baseline; vertices[vertexIndex + 3] += baseline; prevAngleDirection = angleDirection; minBaseLine = Mathf.Min(minBaseLine, baseline.y); maxBaseLine = Mathf.Max(maxBaseLine, baseline.y); } //揃えの計算 if (hAlignment != TextAlignment.Left || vAlignment != TextVAlignment.Base) { float hOffset = 0; if (hAlignment == TextAlignment.Center) { hOffset = (prevOffsetToMidBaseline.x - baseline.x) * 0.5f; } else if (hAlignment == TextAlignment.Right) { hOffset = (prevOffsetToMidBaseline.x - baseline.x); } float vOffset = 0; if (vAlignment == TextVAlignment.Bottom) { vOffset = defaultBaseLine - minBaseLine; } else if (vAlignment == TextVAlignment.Top) { vOffset = defaultBaseLine - maxBaseLine; } Vector3 alignOffset = new Vector3(hOffset, vOffset, 0); for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } int vertexIndex = textInfo.characterInfo[i].vertexIndex; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; vertices[vertexIndex + 0] += alignOffset; vertices[vertexIndex + 1] += alignOffset; vertices[vertexIndex + 2] += alignOffset; vertices[vertexIndex + 3] += alignOffset; } } textComponent.UpdateVertexData(); }
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)); } }
void Update() { if (mode == 0) { // Set the TMP object to show all of the currentDialog string, so we can // calculate line lengths in order to show characters one at a time. tmp.text = currentDialog; tmp.maxVisibleLines = 3; // Need to call this for GetTextInfo() to work. tmp.ForceMeshUpdate(); mode = 1; // Use the lastCharacterIndex of each line to split up the source string into lines, // in order to manage line display TMP_LineInfo[] lineInfoList = tmp.GetTextInfo(tmp.text).lineInfo; lineStrings = new List <string>(); foreach (TMP_LineInfo lineInfo in lineInfoList) { int last = lineInfo.lastCharacterIndex; int first = lineInfo.firstCharacterIndex; // Not sure why but lineinfo has garbage at the end where first/last are zero, so stop in this case. if (first == 0 && last == 0) { break; } // sometimes line infos go past whats visible idk why if (first >= currentDialog.Length) { break; } lineStrings.Add(currentDialog.Substring(first, (last - first) + 1)); } // Keeps track of where to start pulling lines out of lineStrings currentLineIndex = 0; setLines(tmp, lineStrings, currentLineIndex, tmp.maxVisibleLines); tmp.maxVisibleCharacters = 0; } else if (mode == 1) { tmp.maxVisibleCharacters++; if (tmp.maxVisibleCharacters >= tmp.GetTextInfo(tmp.text).characterCount) { mode = 2; } } else if (mode == 2 && Input.GetButtonDown("Jump")) { // remove the first line. currentLineIndex++; // If this is true then the last line of dialogue already finished, so exit (or reset in this case.) if (currentLineIndex > lineStrings.Count - tmp.maxVisibleLines) { mode = 3; tmp.text = ""; } else { setLines(tmp, lineStrings, currentLineIndex, tmp.maxVisibleLines); tmp.maxVisibleCharacters = tmp.GetTextInfo(tmp.text).lineInfo[tmp.maxVisibleLines - 2].lastCharacterIndex; mode = 1; } } else if (mode == 3) { // Do nothing, text is done for now. } }
public override void SetQuestion(Question q, UnityAction <Question> answeredEvent, UISkinData skinData) { base.SetQuestion(q, answeredEvent, skinData); instructionsText.text = question.instructions; idText.text = question.id; toggles = new List <Toggle>(); checkQuestion = (question as CheckListQuestion); gridLayout.startAxis = VariableGridLayoutGroup.Axis.Horizontal; int factor = checkQuestion.questions.Length / maxQuestionsVertical; factor = (factor == 0 ? 1 : factor); //if(checkQuestion.horizontal) { // gridLayout.constraint = VariableGridLayoutGroup.Constraint.FixedRowCount; // gridLayout.constraintCount = 1; // gridLayout.childAlignment = TextAnchor.MiddleCenter; //}else{ gridLayout.constraint = VariableGridLayoutGroup.Constraint.FixedColumnCount; gridLayout.constraintCount = 2 * factor; gridLayout.childAlignment = TextAnchor.MiddleCenter; gridLayout.spacing = spacing; maxWidth = maxTextWidth / factor; maxHeight = maxTextHeight / factor; //} for (int i = 0; i < checkQuestion.questions.Length; i++) { //GameObject labeledItem = Instantiate(checkItemLabeledPrefab); //GameObject checkItem = labeledItem.transform.Find("Checkbox").gameObject; GameObject checkItem = Instantiate(checkItemPrefab); Toggle toggle = checkItem.GetComponent <Toggle>(); toggle.isOn = false; toggle.onValueChanged.AddListener(HandleToggleValueChanged); LayoutElement toggleLayout = toggle.GetComponent <LayoutElement>(); toggleLayout.enabled = true; toggleLayout.minWidth = skinData.toggleSize.x; toggleLayout.minHeight = skinData.toggleSize.y; toggles.Add(toggle); //GameObject label = labeledItem.transform.Find("QuestionLabelInteractive").gameObject; GameObject label = Instantiate(labelPrefab); TMP_Text text = label.GetComponent <TMP_Text>(); text.text = checkQuestion.questions[i].text; text.margin = new Vector4(-spacing.x / 4f, 0, 0, 0); text.autoSizeTextContainer = true; //text.enableAutoSizing = true; text.ForceMeshUpdate(true); LayoutElement labelLayout = label.GetComponent <LayoutElement>(); //float w = text.preferredWidth * preferredWidthScaler; //float h = text.preferredHeight * preferredHeightScaler; ////labelLayout.preferredWidth = - 1; ////labelLayout.preferredHeight = - 1; //labelLayout.preferredWidth = -1; //Mathf.Clamp(w,0,maxWidth); //labelLayout.preferredHeight = -1; // Mathf.Clamp(h,0,maxHeight); if (factor == 1) { labelLayout.flexibleWidth = skinData.canvasSize.x * 0.6f; // 10; labelLayout.preferredWidth = skinData.canvasSize.x * 0.75f; labelLayout.minWidth = -1; labelLayout.minHeight = -1; } if (label.GetComponent <Button>()) { Button btn = label.GetComponent <Button>(); btn.onClick.AddListener(() => { toggle.isOn = !toggle.isOn; }); } //labeledItem.transform.parent = itemsUI; checkItem.transform.parent = itemsUI; label.transform.parent = itemsUI; label.transform.localPosition = new Vector3(0, 0, skinData.radioZOffset); label.transform.localRotation = Quaternion.identity; label.transform.localScale = label.transform.parent.localScale; checkItem.transform.localPosition = new Vector3(0, 0, skinData.radioZOffset); //checkItem.transform.localPosition = Vector3.zero; checkItem.transform.localRotation = Quaternion.identity; checkItem.transform.localScale = label.transform.parent.localScale; } LayoutRebuilder.ForceRebuildLayoutImmediate(itemsUI); }
/// <summary> /// Update /// </summary> protected void Update() { //if the text and the parameters are the same of the old frame, don't waste time in re-computing everything if (!m_forceUpdate && !m_TextComponent.havePropertiesChanged && !ParametersHaveChanged()) { return; } m_forceUpdate = false; //during the loop, vertices represents the 4 vertices of a single character we're analyzing, //while matrix is the roto-translation matrix that will rotate and scale the characters so that they will //follow the curve Vector3[] vertices; Matrix4x4 matrix; //Generate the mesh and get information about the text and the characters m_TextComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = m_TextComponent.textInfo; int characterCount = textInfo.characterCount; //if the string is empty, no need to waste time if (characterCount == 0) { return; } //gets the bounds of the rectangle that contains the text float boundsMinX = m_TextComponent.bounds.min.x; float boundsMaxX = m_TextComponent.bounds.max.x; //for each character for (int i = 0; i < characterCount; i++) { //skip if it is invisible if (!textInfo.characterInfo[i].isVisible) { continue; } //Get the index of the mesh used by this character, then the one of the material... and use all this data to get //the 4 vertices of the rect that encloses this character. Store them in vertices int vertexIndex = textInfo.characterInfo[i].vertexIndex; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; //Compute the baseline mid point for each character. This is the central point of the character. //we will use this as the point representing this character for the geometry transformations Vector3 charMidBaselinePos = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //remove the central point from the vertices point. After this operation, every one of the four vertices //will just have as coordinates the offset from the central position. This will come handy when will deal with the rotations vertices[vertexIndex + 0] += -charMidBaselinePos; vertices[vertexIndex + 1] += -charMidBaselinePos; vertices[vertexIndex + 2] += -charMidBaselinePos; vertices[vertexIndex + 3] += -charMidBaselinePos; //compute the horizontal position of the character relative to the bounds of the box, in a range [0, 1] //where 0 is the left border of the text and 1 is the right border float zeroToOnePos = (charMidBaselinePos.x - boundsMinX) / (boundsMaxX - boundsMinX); //get the transformation matrix, that maps the vertices, seen as offset from the central character point, to their final //position that follows the curve matrix = ComputeTransformationMatrix(charMidBaselinePos, zeroToOnePos, textInfo, i); //apply the transformation, and obtain the final position and orientation of the 4 vertices representing this char 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]); } //Upload the mesh with the revised information m_TextComponent.UpdateVertexData(); }
public void TypeInstantly(TMP_Text textMeshPro) { StopCoroutine(revealTextCoroutine); textMeshPro.maxVisibleCharacters = totalVisibleCharacters; textMeshPro.ForceMeshUpdate(); }
void RevealCharacters(TMP_Text textComponent) { textComponent.ForceMeshUpdate(); textComponent.maxVisibleCharacters = textComponent.textInfo.characterCount; }
private float CalculateHeight() { content.ForceMeshUpdate(); return(Mathf.Clamp(content.textInfo.lineCount * SIZE_PER_LINE, 120, 600)); }
/// <summary> /// Method to curve text along a Unity animation curve. /// </summary> /// <param name="textComponent"></param> /// <returns></returns> IEnumerator WarpText() { VertexCurve.preWrapMode = WrapMode.Clamp; VertexCurve.postWrapMode = WrapMode.Clamp; //Mesh mesh = m_TextComponent.textInfo.meshInfo[0].mesh; Vector3[] vertices; Matrix4x4 matrix; m_TextComponent.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated. CurveScale *= 10; float old_CurveScale = CurveScale; float old_ShearValue = ShearAmount; AnimationCurve old_curve = CopyAnimationCurve(VertexCurve); while (true) { if (!m_TextComponent.havePropertiesChanged && old_CurveScale == CurveScale && old_curve.keys[1].value == VertexCurve.keys[1].value && old_ShearValue == ShearAmount) { yield return(null); continue; } old_CurveScale = CurveScale; old_curve = CopyAnimationCurve(VertexCurve); old_ShearValue = ShearAmount; m_TextComponent.ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate. TMP_TextInfo textInfo = m_TextComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount == 0) { continue; } /* * if(characterCount < 12) * { * int rem = 12 - characterCount; * int addFront = rem / 2; * int addBack = addFront + rem % 2; * * } */ //vertices = textInfo.meshInfo[0].vertices; //int lastVertexIndex = textInfo.characterInfo[characterCount - 1].vertexIndex; float boundsMinX = m_TextComponent.bounds.min.x; //textInfo.meshInfo[0].mesh.bounds.min.x; float boundsMaxX = m_TextComponent.bounds.max.x; //textInfo.meshInfo[0].mesh.bounds.max.x; for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } if (textInfo.characterInfo[i].character == '$') { //Debug.Log("Char was a $"); // Get the index of the material used by the current character. int a = textInfo.characterInfo[i].materialReferenceIndex; // Get the vertex colors of the mesh used by this text element (character or sprite). Color32[] newVertexColors = textInfo.meshInfo[a].colors32; // Get the index of the first vertex used by this text element. int vI = textInfo.characterInfo[i].vertexIndex; Color32 c0 = new Color32((byte)Random.Range(0, 255), (byte)Random.Range(0, 255), (byte)Random.Range(0, 255), 0); newVertexColors[vI + 0] = c0; newVertexColors[vI + 1] = c0; newVertexColors[vI + 2] = c0; newVertexColors[vI + 3] = c0; // New function which pushes (all) updated vertex data to the appropriate meshes when using either the Mesh Renderer or CanvasRenderer. m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); } int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the index of the mesh used by this character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; // Compute the baseline mid point for each character Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //float offsetY = VertexCurve.Evaluate((float)i / characterCount + loopCount / 50f); // Random.Range(-0.25f, 0.25f); // Apply offset to adjust our pivot point. vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; // Apply the Shearing FX float shear_value = ShearAmount * 0.01f; Vector3 topShear = new Vector3(shear_value * (textInfo.characterInfo[i].topRight.y - textInfo.characterInfo[i].baseLine), 0, 0); Vector3 bottomShear = new Vector3(shear_value * (textInfo.characterInfo[i].baseLine - textInfo.characterInfo[i].bottomRight.y), 0, 0); vertices[vertexIndex + 0] += -bottomShear; vertices[vertexIndex + 1] += topShear; vertices[vertexIndex + 2] += topShear; vertices[vertexIndex + 3] += -bottomShear; // Compute the angle of rotation for each character based on the animation curve float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. float x1 = x0 + 0.0001f; float y0 = VertexCurve.Evaluate(x0) * CurveScale; float y1 = VertexCurve.Evaluate(x1) * CurveScale; Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - offsetToMidBaseline.x, 0); Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) - new Vector3(offsetToMidBaseline.x, y0); float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; Vector3 cross = Vector3.Cross(horizontal, tangent); float angle = cross.z > 0 ? dot : 360 - dot; matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), 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] += offsetToMidBaseline; vertices[vertexIndex + 1] += offsetToMidBaseline; vertices[vertexIndex + 2] += offsetToMidBaseline; vertices[vertexIndex + 3] += offsetToMidBaseline; } // Upload the mesh with the revised information m_TextComponent.UpdateVertexData(); yield return(null); // new WaitForSeconds(0.025f); } }
/// <summary> /// Method to animate vertex colors of a TMP Text object. /// </summary> /// <returns></returns> IEnumerator AnimateVertexColors() { // Need to force the text object to be generated so we have valid data to work with right from the start. m_TextComponent.ForceMeshUpdate(); yield return(new WaitForSeconds(0.1f)); TMP_TextInfo textInfo = m_TextComponent.textInfo; Color32[] newVertexColors; int currentCharacter = 0; int startingCharacterRange = currentCharacter; bool isRangeMax = false; while (!isRangeMax) { int characterCount = textInfo.characterCount; // Spread should not exceed the number of characters. byte fadeSteps = (byte)Mathf.Max(1, 255 / RolloverCharacterSpread); for (int i = startingCharacterRange; i < currentCharacter + 1; i++) { // Skip characters that are not visible if (!textInfo.characterInfo[i].isVisible) { continue; } // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the vertex colors of the mesh used by this text element (character or sprite). newVertexColors = textInfo.meshInfo[materialIndex].colors32; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the current character's alpha value. byte alpha = (byte)Mathf.Clamp(newVertexColors[vertexIndex + 0].a - fadeSteps, 0, 255); // Set new alpha values. newVertexColors[vertexIndex + 0].a = alpha; newVertexColors[vertexIndex + 1].a = alpha; newVertexColors[vertexIndex + 2].a = alpha; newVertexColors[vertexIndex + 3].a = alpha; // Tint vertex colors // Note: Vertex colors are Color32 so we need to cast to Color to multiply with tint which is Color. newVertexColors[vertexIndex + 0] = (Color)newVertexColors[vertexIndex + 0] * ColorTint; newVertexColors[vertexIndex + 1] = (Color)newVertexColors[vertexIndex + 1] * ColorTint; newVertexColors[vertexIndex + 2] = (Color)newVertexColors[vertexIndex + 2] * ColorTint; newVertexColors[vertexIndex + 3] = (Color)newVertexColors[vertexIndex + 3] * ColorTint; if (alpha == 0) { startingCharacterRange += 1; if (startingCharacterRange == characterCount) { // Update mesh vertex data one last time. m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); yield return(new WaitForSeconds(1.0f)); Destroy(this.gameObject); // Reset the text object back to original state. m_TextComponent.ForceMeshUpdate(); yield return(new WaitForSeconds(1.0f)); // Reset our counters. currentCharacter = 0; startingCharacterRange = 0; isRangeMax = true; // Would end the coroutine. } } } // Upload the changed vertex colors to the Mesh. m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); if (currentCharacter + 1 < characterCount) { currentCharacter += 1; } yield return(new WaitForSeconds(0.25f - FadeSpeed * 0.01f)); } Destroy(this.gameObject); }
private void OnDrawGizmos() { if (m_TextComponent == null) { m_TextComponent = GetComponent <TMP_Text>(); if (m_TextComponent == null) { return; } } m_TextComponent.ForceMeshUpdate(); m_Transform = m_TextComponent.transform; // Get a reference to the text object's textInfo m_TextInfo = m_TextComponent.textInfo; // Update Text Statistics ObjectStats = "Characters: " + m_TextInfo.characterCount + " Words: " + m_TextInfo.wordCount + " Spaces: " + m_TextInfo.spaceCount + " Sprites: " + m_TextInfo.spriteCount + " Links: " + m_TextInfo.linkCount + "\nLines: " + m_TextInfo.lineCount + " Pages: " + m_TextInfo.pageCount; // Get the handle size for drawing the various m_ScaleMultiplier = m_TextComponent.GetType() == typeof(TextMeshPro) ? 1 : 0.1f; m_HandleSize = HandleUtility.GetHandleSize(m_Transform.position) * m_ScaleMultiplier; // Draw line metrics #region Draw Lines if (ShowLines) { DrawLineBounds(); } #endregion // Draw word metrics #region Draw Words if (ShowWords) { DrawWordBounds(); } #endregion // Draw character metrics #region Draw Characters if (ShowCharacters) { DrawCharactersBounds(); } #endregion // Draw Quads around each of the words #region Draw Links if (ShowLinks) { DrawLinkBounds(); } #endregion // Draw Quad around the bounds of the text #region Draw Bounds if (ShowMeshBounds) { DrawBounds(); } #endregion // Draw Quad around the rendered region of the text. #region Draw Text Bounds if (ShowTextBounds) { DrawTextBounds(); } #endregion }
void UpdateCurveMesh() { textComponent.ForceMeshUpdate(); TMP_TextInfo textInfo = textComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount == 0) { return; } float boundsMinX = textComponent.bounds.min.x; float boundsMaxX = textComponent.bounds.max.x; Vector3[] vertices; Matrix4x4 matrix; for (int i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } int vertexIndex = textInfo.characterInfo[i].vertexIndex; int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; //文字の真ん中の点と文字の基準となるベースラインの高さを取得 Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //文字の中央の下が原点となるように頂点を移動(これから回転と移動をさせるため) vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; //カーブの傾きに沿って,文字サイズかけてどの程度傾けるかを計算 //float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. //float x1 = x0 + 0.0001f; //float y0 = vertexCurve.Evaluate(x0) * curveScale; //float y1 = vertexCurve.Evaluate(x1) * curveScale; //float charSize = boundsMaxX - boundsMinX; //Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 tangent = new Vector3(charSize * 0.0001f, y1 - y0); //float angle = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * Mathf.Rad2Deg; //Vector3 cross = Vector3.Cross(horizontal, tangent); //angle = cross.z > 0 ? angle : 360 - angle; float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. float y0 = vertexCurve.Evaluate(x0) * curveScale; //angle回転させて,baseをy0だけあげるた頂点位置の計算 matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), 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] += offsetToMidBaseline; vertices[vertexIndex + 1] += offsetToMidBaseline; vertices[vertexIndex + 2] += offsetToMidBaseline; vertices[vertexIndex + 3] += offsetToMidBaseline; } textComponent.UpdateVertexData(); }
IEnumerator AnimateVertices() { //Debug.Log("start"); animating = true; if (!initialized) { yield return(new WaitForEndOfFrame()); } // 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; // Cache the vertex data of the text object as the translate FX is applied to the original position of the characters. TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); Color32[] newVertexColors; Color32 c0 = m_TextComponent.color; //start time of this whole animation float animStartTime = Time.time; while (animating) { int characterCount = textInfo.characterCount; 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; } // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[i].materialReferenceIndex; // Get the vertex colors of the mesh used by this text element (character or sprite). newVertexColors = textInfo.meshInfo[materialIndex].colors32; // 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; // calculate the pivot for each character. default to center Vector2 charPivot = Vector2.zero; switch (pivot) { case LetterPivot.baselineCenter: charPivot = new Vector2((sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x) / 2, charInfo.baseLine); break; case LetterPivot.baselineLeft: charPivot = new Vector2(sourceVertices[vertexIndex + 0].x, charInfo.baseLine); break; case LetterPivot.baselineRight: charPivot = new Vector2(sourceVertices[vertexIndex + 0].x + sourceVertices[vertexIndex + 2].x, charInfo.baseLine); break; default: //center charPivot = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; break; } // 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 = charPivot; 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; //progress through the animation float p = Mathf.Clamp01((Time.time - (animStartTime + (i * letterDelay))) / duration); //ANIMATION MAGIC HAPPENS HERE Vector3 currentTranslate = LetterTranslateFunction(p, i, characterCount); Quaternion currentRotate = LetterRotateFunction(p, i, characterCount); Vector3 currentScale = LetterScaleFunction(p, i, characterCount); //ok magic's over pass in that magic matrix = Matrix4x4.TRS(currentTranslate, currentRotate, currentScale); 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; //apply color animation // Only change the vertex color if the text element is visible. if (textInfo.characterInfo[i].isVisible) { //color animation magic happens here!!! c0 = LetterColorFunction(c0, p, i, characterCount); //kk magic's over pass it all to the verticies newVertexColors[vertexIndex + 0] = c0; newVertexColors[vertexIndex + 1] = c0; newVertexColors[vertexIndex + 2] = c0; newVertexColors[vertexIndex + 3] = c0; // New function which pushes (all) updated vertex data to the appropriate meshes when using either the Mesh Renderer or CanvasRenderer. m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); // This last process could be done to only update the vertex data that has changed as opposed to all of the vertex data but it would require extra steps and knowing what type of renderer is used. // These extra steps would be a performance optimization but it is unlikely that such optimization will be necessary. } //if the last character has finished its animation progression, set animating to false if (i == characterCount - 1 && p >= 1f) { animating = false; //Debug.Log("stopped"); OnAnimationComplete(); } } // Push changes into meshes 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); } yield return(new WaitForEndOfFrame()); } }
public void CreateWordList(int currentLetter) { words = new List <string>(); foreach (string w in wp.parsedWords[currentLetter]) { words.Add(w); } panel_start = true; current_word_index = 0; panel_count = 0; TypeInput[] ip = FindObjectsOfType <TypeInput>(); foreach (TypeInput t in ip) { Destroy(t.transform.parent.gameObject); } while (current_word_index < words.Count) { if (panel_start) { space_in_line = new List <int>(); Debug.Log("create"); panel_start = false; current_panel = Instantiate(template_panel); current_panel.transform.SetParent(parent.transform, false); panel = current_panel.GetComponent <TextPanel>(); panel.order_num = panel_count; panel.user_panel.orderNum = panel.order_num; } else { for (int i = current_word_index; i <= words.Count; i++) { current_word_index = i; if (current_word_index == words.Count) { break; } Debug.Log(panel); TMP_Text tempText = panel.panel_text; string beforeChange = panel.panel_text.text; tempText.text += words[current_word_index]; tempText.ForceMeshUpdate(); if (words[current_word_index].Contains("\n")) { string[] b = words[current_word_index].Split('\n'); panel.panel_text.text = beforeChange + b[0]; words.Insert(current_word_index + 1, b[1]); panel_start = true; panel_count++; current_word_index++; break; } else if (tempText.isTextOverflowing && !words[current_word_index].Contains("\n")) { Debug.Log("Overflow at " + words[current_word_index]); panel.panel_text.text = beforeChange; GameManager.instance.space_breaks.Add(space_in_line); current_space_index = 0; //current_word_index -= 1; panel_start = true; panel_count++; break; } if (i != words.Count - 1) { panel.panel_text.text += " "; } panel.panel_text = tempText; } if (current_word_index == 150) { break; } } } }
public void AdjustDiacriticPositions() { m_TextComponent = gameObject.GetComponent <TMP_Text>(); m_TextComponent.ForceMeshUpdate(); textInfo = m_TextComponent.textInfo; int characterCount = textInfo.characterCount; if (characterCount > 1) { int newYOffset = 0; int charPosition = 1; if (ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[0].character) == "0627" && ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[1].character) == "064B") { newYOffset = 10; } if (ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[0].character) == "0623" && ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[1].character) == "064E") { newYOffset = 16; } if (ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[0].character) == "0639" && ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[1].character) == "0650") { newYOffset = -25; } if (newYOffset != 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(); // Get the index of the material used by the current character. int materialIndex = textInfo.characterInfo[charPosition].materialReferenceIndex; // Get the index of the first vertex used by this text element. int vertexIndex = textInfo.characterInfo[charPosition].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. float dy = (sourceVertices[vertexIndex + 2].y - sourceVertices[vertexIndex + 0].y); Vector3 offset = new Vector3(0f, dy, 0f); 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; 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("DIACRITIC: diacritic pos fixed for " + // ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[1].character) + " by " + newYOffset); } //for (int i = 0; i < characterCount; i++) { // Debug.Log("DIACRITIC: " + i // //+ "index: " + textInfo.characterInfo[i].index // + " char: " + textInfo.characterInfo[i].character.ToString() // + " UNICODE: " + ArabicAlphabetHelper.GetHexUnicodeFromChar(textInfo.characterInfo[i].character) // ); //} } }
/// <summary> /// Method to curve text along a Unity animation curve. /// </summary> /// <param name="textComponent"></param> /// <returns></returns> private IEnumerator WarpText() { VertexCurve.preWrapMode = WrapMode.Clamp; VertexCurve.postWrapMode = WrapMode.Clamp; //Mesh mesh = m_TextComponent.textInfo.meshInfo[0].mesh; Vector3[] vertices; Matrix4x4 matrix; m_TextComponent.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated. CurveScale *= 10; var old_CurveScale = CurveScale; var old_curve = CopyAnimationCurve(VertexCurve); while (true) { if (!m_TextComponent.havePropertiesChanged && old_CurveScale == CurveScale && old_curve.keys[1].value == VertexCurve.keys[1].value) { yield return(null); continue; } old_CurveScale = CurveScale; old_curve = CopyAnimationCurve(VertexCurve); m_TextComponent .ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate. var textInfo = m_TextComponent.textInfo; var characterCount = textInfo.characterCount; if (characterCount == 0) { continue; } //vertices = textInfo.meshInfo[0].vertices; //int lastVertexIndex = textInfo.characterInfo[characterCount - 1].vertexIndex; var boundsMinX = m_TextComponent.bounds.min.x; //textInfo.meshInfo[0].mesh.bounds.min.x; var boundsMaxX = m_TextComponent.bounds.max.x; //textInfo.meshInfo[0].mesh.bounds.max.x; for (var i = 0; i < characterCount; i++) { if (!textInfo.characterInfo[i].isVisible) { continue; } var vertexIndex = textInfo.characterInfo[i].vertexIndex; // Get the index of the mesh used by this character. var materialIndex = textInfo.characterInfo[i].materialReferenceIndex; vertices = textInfo.meshInfo[materialIndex].vertices; // Compute the baseline mid point for each character Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine); //float offsetY = VertexCurve.Evaluate((float)i / characterCount + loopCount / 50f); // Random.Range(-0.25f, 0.25f); // Apply offset to adjust our pivot point. vertices[vertexIndex + 0] += -offsetToMidBaseline; vertices[vertexIndex + 1] += -offsetToMidBaseline; vertices[vertexIndex + 2] += -offsetToMidBaseline; vertices[vertexIndex + 3] += -offsetToMidBaseline; // Compute the angle of rotation for each character based on the animation curve var x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh. var x1 = x0 + 0.0001f; var y0 = VertexCurve.Evaluate(x0) * CurveScale; var y1 = VertexCurve.Evaluate(x1) * CurveScale; var horizontal = new Vector3(1, 0, 0); //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - offsetToMidBaseline.x, 0); var tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) - new Vector3(offsetToMidBaseline.x, y0); var dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; var cross = Vector3.Cross(horizontal, tangent); var angle = cross.z > 0 ? dot : 360 - dot; matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), 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] += offsetToMidBaseline; vertices[vertexIndex + 1] += offsetToMidBaseline; vertices[vertexIndex + 2] += offsetToMidBaseline; vertices[vertexIndex + 3] += offsetToMidBaseline; } // Upload the mesh with the revised information m_TextComponent.UpdateVertexData(); yield return(new WaitForSeconds(0.025f)); } }
public IEnumerator AnimateTextIn(List <DialogueCommand> commands, string processedMessage, AudioClip voice_sound, Action onFinish) { textAnimating = true; float secondsPerCharacter = 1f / 150f; float timeOfLastCharacter = 0; TextAnimInfo[] textAnimInfo = SeparateOutTextAnimInfo(commands); TMP_TextInfo textInfo = textBox.textInfo; for (int i = 0; i < textInfo.meshInfo.Length; i++) //Clear the mesh { TMP_MeshInfo meshInfer = textInfo.meshInfo[i]; if (meshInfer.vertices != null) { for (int j = 0; j < meshInfer.vertices.Length; j++) { meshInfer.vertices[j] = vecZero; } } } textBox.text = processedMessage; textBox.ForceMeshUpdate(); TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData(); Color32[][] originalColors = new Color32[textInfo.meshInfo.Length][]; for (int i = 0; i < originalColors.Length; i++) { Color32[] theColors = textInfo.meshInfo[i].colors32; originalColors[i] = new Color32[theColors.Length]; Array.Copy(theColors, originalColors[i], theColors.Length); } int charCount = textInfo.characterCount; float[] charAnimStartTimes = new float[charCount]; for (int i = 0; i < charCount; i++) { charAnimStartTimes[i] = -1; //indicate the character as not yet started animating. } int visableCharacterIndex = 0; while (true) { if (stopAnimating) { for (int i = visableCharacterIndex; i < charCount; i++) { charAnimStartTimes[i] = Time.unscaledTime; } visableCharacterIndex = charCount; FinishAnimating(onFinish); } if (ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) { if (visableCharacterIndex <= charCount) { ExecuteCommandsForCurrentIndex(commands, visableCharacterIndex, ref secondsPerCharacter, ref timeOfLastCharacter); if (visableCharacterIndex < charCount && ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) { charAnimStartTimes[visableCharacterIndex] = Time.unscaledTime; PlayDialogueSound(voice_sound); visableCharacterIndex++; timeOfLastCharacter = Time.unscaledTime; if (visableCharacterIndex == charCount) { FinishAnimating(onFinish); } } } } for (int j = 0; j < charCount; j++) { TMP_CharacterInfo charInfo = textInfo.characterInfo[j]; if (charInfo.isVisible) //Invisible characters have a vertexIndex of 0 because they have no vertices and so they should be ignored to avoid messing up the first character in the string whic also has a vertexIndex of 0 { int vertexIndex = charInfo.vertexIndex; int materialIndex = charInfo.materialReferenceIndex; Color32[] destinationColors = textInfo.meshInfo[materialIndex].colors32; Color32 theColor = j < visableCharacterIndex ? originalColors[materialIndex][vertexIndex] : clear; destinationColors[vertexIndex + 0] = theColor; destinationColors[vertexIndex + 1] = theColor; destinationColors[vertexIndex + 2] = theColor; destinationColors[vertexIndex + 3] = theColor; Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices; Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices; float charSize = 0; float charAnimStartTime = charAnimStartTimes[j]; if (charAnimStartTime >= 0) { float timeSinceAnimStart = Time.unscaledTime - charAnimStartTime; charSize = Mathf.Min(1, timeSinceAnimStart / CHAR_ANIM_TIME); } Vector3 animPosAdjustment = GetAnimPosAdjustment(textAnimInfo, j, textBox.fontSize, Time.unscaledTime); Vector3 offset = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2; destinationVertices[vertexIndex + 0] = ((sourceVertices[vertexIndex + 0] - offset) * charSize) + offset + animPosAdjustment; destinationVertices[vertexIndex + 1] = ((sourceVertices[vertexIndex + 1] - offset) * charSize) + offset + animPosAdjustment; destinationVertices[vertexIndex + 2] = ((sourceVertices[vertexIndex + 2] - offset) * charSize) + offset + animPosAdjustment; destinationVertices[vertexIndex + 3] = ((sourceVertices[vertexIndex + 3] - offset) * charSize) + offset + animPosAdjustment; } } textBox.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); for (int i = 0; i < textInfo.meshInfo.Length; i++) { TMP_MeshInfo theInfo = textInfo.meshInfo[i]; theInfo.mesh.vertices = theInfo.vertices; textBox.UpdateGeometry(theInfo.mesh, i); } yield return(null); } }
// Shaking example taken from the TextMeshPro demo. private IEnumerator ShakeTextAt(int startIndex, int endIndex) { // 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. Text.ForceMeshUpdate(); TMP_TextInfo textInfo = Text.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 == 0) { yield return(new WaitForSeconds(0.25f)); continue; } for (int i = startIndex; i < endIndex; 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; Text.UpdateGeometry(textInfo.meshInfo[i].mesh, i); } loopCount += 1; yield return(new WaitForSeconds(0.1f)); } }
private void StripCommandsFromTextAndCreateCommandList(string text) { SentenceUIObject.text = StripAllCommands(text); SentenceUIObject.ForceMeshUpdate(); specialCommands = BuildSpecialCommandList(text); }