예제 #1
0
        private void UpdateTextAnimation()
        {
            dialogueBoxLabel.ForceMeshUpdate();

            TMP_TextInfo textInfo = dialogueBoxLabel.textInfo;

            Vector3[] vertices = dialogueBoxLabel.mesh.vertices;

            Matrix4x4 matrix;

            Color32[] vertexColors;

            bool areAllCharactersFullAlpha = true;

            for (int i = 0; i < dialogueBoxLabel.textInfo.characterCount; i++)
            {
                TMP_CharacterInfo charInfo = textInfo.characterInfo[i];

                // Skip this character if it is not visible
                if (!charInfo.isVisible)
                {
                    continue;
                }

                int vertexIndex   = charInfo.vertexIndex;
                int materialIndex = charInfo.materialReferenceIndex;
                vertexColors = textInfo.meshInfo[materialIndex].colors32;

                // Calculate the current alpha for each letter depending on whether it is fading/faded in or out
                float alpha = 0f;

                if (showText)
                {
                    if (typewriterInProgress && textAnimationData != null)
                    {
                        TextAnimationData animationData = textAnimationData[i];
                        float             animationTime = Time.unscaledTime - typewriterStartTime - animationData.fadeInDelay;
                        alpha = Mathf.Clamp01(animationTime / animationData.fadeInDuration);
                    }
                    else
                    {
                        alpha = 1f;
                    }
                }
                else
                {
                    float animationTime = Time.unscaledTime - fadeOutStartTime;
                    alpha = 1f - Mathf.Clamp01(animationTime / fadeOutDuration);
                }

                // Keep track of whether all characters are fully visible for the sake of knowing when
                // the typewriter animation has finished.
                if (areAllCharactersFullAlpha && !Mathf.Approximately(alpha, 1f))
                {
                    areAllCharactersFullAlpha = false;
                }

                // Set the character's alpha
                Color32 color = charInfo.color;
                color.a = (byte)(255 * alpha);

                vertexColors[vertexIndex + 0] = color;
                vertexColors[vertexIndex + 1] = color;
                vertexColors[vertexIndex + 2] = color;
                vertexColors[vertexIndex + 3] = color;

                // Animate vertex positions
                if (textAnimationData != null && textAnimationData[i].animationStyle != null)
                {
                    TextAnimationData animationData          = textAnimationData[i];
                    float             typewriterTime         = Time.unscaledTime - typewriterStartTime - animationData.fadeInDelay;
                    DialogueManager.TextAnimationStyle style = animationData.animationStyle;

                    // We want character animations to pivot at the character's center, so offset
                    // the vertices before we do any transformations
                    Vector3 offset = (charInfo.topLeft + charInfo.bottomRight) / 2;

                    vertices[vertexIndex + 0] -= offset;
                    vertices[vertexIndex + 1] -= offset;
                    vertices[vertexIndex + 2] -= offset;
                    vertices[vertexIndex + 3] -= offset;

                    // Calculate the animated translation, rotation and scale of the character
                    Vector3 translation = Vector3.zero;
                    if (style.translation.type != DialogueManager.TextAnimationStyle.Type.None)
                    {
                        float animationFactor = Mathf.Sin((Time.time - style.translation.delayPerCharacter * i) * Mathf.PI / style.translation.duration);
                        if (style.translation.type == DialogueManager.TextAnimationStyle.Type.Bounce)
                        {
                            animationFactor = Mathf.Abs(animationFactor);
                        }
                        translation = style.translation.offset * animationFactor;
                    }
                    if (style.translateIn.x.length > 0 && typewriterTime > 0f && typewriterTime <= style.translateIn.x.keys[style.translateIn.x.length - 1].time)
                    {
                        translation.x += style.translateIn.x.Evaluate(typewriterTime);
                    }
                    if (style.translateIn.y.length > 0 && typewriterTime > 0f && typewriterTime <= style.translateIn.y.keys[style.translateIn.y.length - 1].time)
                    {
                        translation.y += style.translateIn.y.Evaluate(typewriterTime);
                    }

                    Quaternion rotation = Quaternion.identity;
                    float      angle    = 0f;
                    if (style.rotation.type != DialogueManager.TextAnimationStyle.Type.None)
                    {
                        float animationFactor = Mathf.Sin((Time.time - style.rotation.delayPerCharacter * i) * Mathf.PI / style.rotation.duration);
                        if (style.rotation.type == DialogueManager.TextAnimationStyle.Type.Bounce)
                        {
                            animationFactor = Mathf.Abs(animationFactor);
                        }
                        angle = style.rotation.startAngle + style.rotation.angleOffset * animationFactor;
                    }
                    if (style.rotateIn.length > 0 && typewriterTime > 0f && typewriterTime <= style.rotateIn.keys[style.rotateIn.length - 1].time)
                    {
                        angle += style.rotateIn.Evaluate(typewriterTime);
                    }
                    rotation = Quaternion.Euler(0f, 0f, angle);

                    Vector3 scale = Vector3.one;
                    if (style.scale.type != DialogueManager.TextAnimationStyle.Type.None)
                    {
                        float animationFactor = Mathf.Sin((Time.time - style.scale.delayPerCharacter * i) * Mathf.PI / style.scale.duration);
                        if (style.scale.type == DialogueManager.TextAnimationStyle.Type.Bounce)
                        {
                            animationFactor = Mathf.Abs(animationFactor);
                        }
                        scale   = style.scale.startScale + style.scale.scaleOffset * animationFactor;
                        scale.z = 1f;
                    }
                    if (style.scaleIn.x.length > 0 && typewriterTime > 0f && typewriterTime <= style.scaleIn.x.keys[style.scaleIn.x.length - 1].time)
                    {
                        scale.x *= style.scaleIn.x.Evaluate(typewriterTime);
                    }
                    if (style.scaleIn.y.length > 0 && typewriterTime > 0f && typewriterTime <= style.scaleIn.y.keys[style.scaleIn.y.length - 1].time)
                    {
                        scale.y *= style.scaleIn.y.Evaluate(typewriterTime);
                    }

                    // Apply the calculated transformations
                    matrix = Matrix4x4.TRS(translation, rotation, scale);

                    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]);

                    // Undo the offset to put the character back in the right place
                    vertices[vertexIndex + 0] += offset;
                    vertices[vertexIndex + 1] += offset;
                    vertices[vertexIndex + 2] += offset;
                    vertices[vertexIndex + 3] += offset;
                }
            }

            // Mark the typewriter animation as over once all characters are fully visible
            if (typewriterInProgress && areAllCharactersFullAlpha)
            {
                typewriterInProgress = false;
            }

            // Update the mesh
            dialogueBoxLabel.mesh.vertices = vertices;

            dialogueBoxLabel.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
        }
예제 #2
0
        private void InitCharacterAnimationDataFromText(string sourceText)
        {
            textAnimationData = new List <TextAnimationData>();

            // Define animation properties shared between multiple characters
            float totalFadeInDelay      = 0f;
            float delayMultiplier       = 1f;
            float fadeInDuration        = typewriterFadeInDuration;
            bool  readingRichTextMarkup = false;

            DialogueManager.TextAnimationStyle animationStyle = null;

            for (int sourceIndex = 0; sourceIndex < sourceText.Length; sourceIndex++)
            {
                // Define one-time animation properties for this character
                float pauseDuration = 0f;

                // Process character animation markup
                while (sourceText[sourceIndex] == '{')
                {
                    // Read the command from the source text
                    TextAnimationCommand command = new TextAnimationCommand(sourceText, sourceIndex);

                    // Skip the source index ahead to the end of the command
                    if (command.fullText.Length > 0)
                    {
                        sourceIndex += command.fullText.Length;
                    }
                    else
                    {
                        break;
                    }

                    // Process the command:
                    switch (command.command.ToLower())
                    {
                    // Add a one-time pause between characters with the the indicated duration.
                    case "pause":
                    {
                        bool success = (command.args.Length > 0 && float.TryParse(command.args[0], out pauseDuration));
                        if (!success)
                        {
                            Debug.Log("Invalid argument(s) for command 'Pause'.");
                        }
                    }
                    break;

                    // Multiply the delay duration between characters until the end of the line (or until this command is called again).
                    case "multiplydelay":
                    {
                        bool success = (command.args.Length > 0 && float.TryParse(command.args[0], out delayMultiplier));
                        if (!success)
                        {
                            Debug.Log("Invalid argument for command 'MultiplyDelay'.");
                        }
                    }
                    break;

                    // Multiply the fade-in duration for each character until the end of the line (or until this command is called again).
                    case "fadeintime":
                    {
                        bool success = (command.args.Length > 0 && float.TryParse(command.args[0], out fadeInDuration));
                        if (!success)
                        {
                            Debug.Log("Invalid argument for command 'FadeInTime'.");
                        }
                    }
                    break;

                    // Set the animation style for this character and following characters
                    case "animationstyle":
                    {
                        animationStyle = null;
                        if (command.args.Length > 0)
                        {
                            for (int styleIndex = 0; styleIndex < DialogueManager.Instance.textAnimationStyles.Length; styleIndex++)
                            {
                                if (DialogueManager.Instance.textAnimationStyles[styleIndex].name == command.args[0])
                                {
                                    animationStyle = DialogueManager.Instance.textAnimationStyles[styleIndex];
                                    break;
                                }
                            }
                        }
                        if (animationStyle == null)
                        {
                            Debug.LogWarningFormat("Invalid text animation style '{0}'.", command.args[0]);
                        }
                    }
                    break;

                    // Clear the animation style for this character and following characters
                    case "clearanimationstyle":
                    {
                        animationStyle = null;
                    }
                    break;

                    default:
                    {
                        Debug.LogWarningFormat("Unknown command '{0}'.", command.command);
                    }
                    break;
                    }
                }

                // Skip this character if it is rich text markup
                if (sourceText[sourceIndex] == '<')
                {
                    readingRichTextMarkup = true;
                }
                else if (sourceText[sourceIndex] == '>')
                {
                    readingRichTextMarkup = false;
                    continue;
                }
                if (readingRichTextMarkup)
                {
                    continue;
                }

                // Calculate the delay duration for this character (time between the full text's
                // animation beginning and this character appearing).
                totalFadeInDelay += pauseDuration > 0f ? pauseDuration : typewriterCharacterDelay * delayMultiplier;

                // Create the animation data for this character
                TextAnimationData characterData = new TextAnimationData();

                characterData.animationStyle = animationStyle;
                characterData.fadeInDelay    = totalFadeInDelay;
                characterData.fadeInDuration = fadeInDuration;

                textAnimationData.Add(characterData);
            }
        }