Unity入門

【Unity】TextMeshProUGUIで文字アニメーションをスクリプトで実装する方法

この記事について

この記事ではアニメーションをスクリプトと動画で誰でも作れるようにしています。

この記事でわかること

  • TextMeshProUGUIは スクリプトで簡単に文字アニメーションを実装可能
  • タイプライター風(1文字ずつ表示)
  • 点滅やフェード(α値制御)
  • 拡大縮小や揺れ(Transform制御+TMP更新)
  • 揺れ・シェイク演出

TextMeshProUGUIとは?

TextMeshProUGUIについては以下の記事を参考にしてください。

スクリプトでアニメーション実装

TextMeshProUGUIの準備

まずはヒエラルキーで右クリックをしてTextMeshProUGUIを1つ用意します。
・「右クリック」→「UI」→「Text – TextMeshPro」

次にスクリプトを作成して先ほどのTextMeshProUGIにアタッチしてください。
ここまで出来たら準備完了です!

タイプライター風(1文字ずつ表示)

タイプライター風にするには数秒に1文字が表示されるようにならなければいけません。
そこで、今回使用するのが「InvokeRepeating」です。
以下のスクリプトをコピーして実装してみましょう。

using TMPro;
using UnityEngine;

public class TextMeshProUGUI_Animation : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI tmpUGUI; // 表示対象のTextMeshProUGUI
    private float interval = 0.2f;   // 文字を出す間隔(秒)

    private string fullText;      // 全文(アニメーション対象の文字列)
    private string currentText = ""; // 現在表示されている文字列
    private int index = 0;        // 何文字目まで表示したかを管理するカウンタ

    void Start()
    {
        // このスクリプトがアタッチされているオブジェクトからTextMeshProUGUIを取得
        tmpUGUI = GetComponent<TextMeshProUGUI>();

        // 表示する全文を設定(ここでは固定で"This is a pen")
        fullText = "This is a pen";

        // ShowNextCharメソッドを interval 秒ごとに呼び出す
        // 第1引数: 呼び出すメソッド名
        // 第2引数: 最初の呼び出しまでの待ち時間(ここでは0秒)
        // 第3引数: 繰り返しの間隔(ここでは interval 秒)
        InvokeRepeating(nameof(ShowNextChar), 0f, interval);
    }

    void ShowNextChar()
    {
        // まだ全文を表示していない場合
        if (index < fullText.Length)
        {
            // 1文字追加
            currentText += fullText[index];

            // TextMeshProに反映
            tmpUGUI.text = currentText;

            // 次の文字へ進める
            index++;
        }
        else
        {
            // 全文表示が終わったら繰り返し呼び出しを停止
            CancelInvoke(nameof(ShowNextChar));
        }
    }
}

実装するとこのようになります。(TextMeshProUGUIのWidthは調整してください)

点滅・フェード演出

点滅・フェード演出はよく使用するものだと思います。
今回は「Sin」と「Alpha」を使用することで波のように変化させていきます。
以下のスクリプトをコピーして実装してみましょう。

public class TextMeshProUGUI_Animation : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI tmpUGUI; // 表示対象のTextMeshProUGUI
    [SerializeField] private float speed = 2f;

    void Start()
    {
        // このスクリプトがアタッチされているオブジェクトからTextMeshProUGUIを取得
        tmpUGUI = GetComponent<TextMeshProUGUI>();
    }
    void Update()
    {
        float alpha = Mathf.Abs(Mathf.Sin(Time.time * speed));
        tmpUGUI.alpha = alpha;
    }
}

実装するとこのようになります。なかなか実用性が高そうですね。

拡大縮小アニメーション

今回は「Sin」と「localScale」を使用することで波のように変化させていきます。
以下のスクリプトをコピーして実装してみましょう。

public class TextMeshProUGUI_Animation : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI tmpUGUI; // 表示対象のTextMeshProUGUI
    [SerializeField] private float scaleSpeed = 2f;
    [SerializeField] private float scaleRange = 0.2f;

    void Start()
    {
        // このスクリプトがアタッチされているオブジェクトからTextMeshProUGUIを取得
        tmpUGUI = GetComponent<TextMeshProUGUI>();
    }
    void Update()
    {
        float scale = 1 + Mathf.Sin(Time.time * scaleSpeed) * scaleRange;
        tmpUGUI.rectTransform.localScale = new Vector3(scale, scale, 1);
    }
}

実装するとこのようになります。
iOSアプリでよく見ることがあるアニメーション化と思います。

揺れ・シェイク演出

今回は「Sin」と「localPosition」を使用することで揺れを起こしていきます。
以下のスクリプトをコピーして実装してみましょう。

public class TextMeshProUGUI_Animation : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI tmpUGUI; // 表示対象のTextMeshProUGUI
    [SerializeField] private float intensity = 5f; // 揺れの強さ(振れ幅)
    Vector3 basePos;                               // 元の位置を保存しておく変数

    void Start()
    {
        // このスクリプトがアタッチされているオブジェクトの TextMeshProUGUI を取得
        tmpUGUI = GetComponent<TextMeshProUGUI>();

        // 初期位置(基準位置)を記録
        basePos = tmpUGUI.rectTransform.localPosition;
    }

    void Update()
    {
        // 時間に応じて Sin / Cos で座標をずらして「揺れ」を表現
        // x方向: 周期の速さを 50f 倍にしたサイン波
        // y方向: 周期の速さを 60f 倍にしたコサイン波
        // → サイン波とコサイン波を組み合わせて複雑な揺れに見せている
        tmpUGUI.rectTransform.localPosition = basePos +
            new Vector3(
                Mathf.Sin(Time.time * 50f) * intensity, // X方向の揺れ
                Mathf.Cos(Time.time * 60f) * intensity, // Y方向の揺れ
                0                                       // Z方向は固定
            );
    }
}

実装するとこのようになります。
個人的には使用に注意するひつようがあるかなと思います。

まとめ

  • タイプライター風 → ノベル・会話演出に最適
  • 点滅・フェード → タイトル・待機画面で効果的
  • 拡大縮小 → スコア・クリティカルヒットの強調
  • シェイク → 警告やダメージ演出に向いている