Raspberlyのブログ

Raspberlyのブログ

Unityネタをメインとした技術系ブログです。にゃんこ大戦争や日常なども。そろそろブログタイトル決めたい

【Unity】DOTextで日本語を1文字ずつ表示したとき"途中で改行位置が変わる"問題の対処法【TextMeshPro】

この記事はUnityAdventCalendar 2025の記事です。

qiita.com

時間ができたので書きました。

 

 

やること

DOTweenのDOTextを使って日本語テキストを1文字ずつ表示するとき、
日本語の禁則処理が後から適用され、途中で改行位置が変わる現象が起こることがあります。



原因は表示中の改行位置再計算による再レイアウトです。
これが発生しない文字表示方法をまとめます。
PRO版ではない無料のDOTweenでもできるやり方も紹介します

 

 

 

先に答えから

検索でこの記事に来た方は、すぐに解決方法を知りたいと思うので先に書いておきます。
DOText()は使わず、DOMaxVisibleCharacters()で最大表示文字数を変動させる

// DOTextを
text.text = string.Empty;
text.DOText(message, message.Length * writeTimePerChara).SetEase(Ease.Linear);

// DOMaxVisibleCharactersに置き換える text.text = message; text.maxVisibleCharacters = 0; text.ForceMeshUpdate(); text.DOMaxVisibleCharacters(message.Length, message.Length * writeTimePerChara).SetEase(Ease.Linear);

 

 

 

開発環境

Unity 6000.3.0f1

DOTween Pro ver1.0.385

 

 

再現シーン

わかりやすいように再現シーンを用意しました。

 

Canvasを作成し、テキスト(TextMeshPro)と表示範囲を設定。
確認しやすいように改行が発生しやすい設定にしています。

 

まずは通常のDOTextで表示してみます。以下のスクリプトを使用。

using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class TextTest : MonoBehaviour
{
    [SerializeField] private TMP_Text text;
    [SerializeField] private Button button;
    [SerializeField] private string sentence;
    [SerializeField] private float writeTimePerChara = 0.1f;
    private Tween currentTween;
    
    private void Start()
    {
        button.onClick.AddListener(() => WriteText(sentence));
    }
    
    /// <summary>
    /// string型文字列を受け取ってTextに表示
    /// </summary>
    private void WriteText(string message)
    {
        currentTween?.Kill();
        text.text = string.Empty;
        text.ForceMeshUpdate();
        currentTween = text.DOText(message, message.Length * writeTimePerChara).SetEase(Ease.Linear);
    }
    
    private void OnDestroy()
    {
        currentTween?.Kill();
    }
}

 

紐づけたボタンを押せばTextに文字列を表示します。

 

表示する文字列はこちら。改行が起こりやすいような文章にしています。

ここに「日本語テキスト」を表示します。。。。急に改行が入ったりするかを確認だ。

 

 

実行するとこんな感じ。
禁則処理によって、すでに表示されている文字が改行されています。

 

 

DOTextからの置き換え(DOMaxVisibleCharacters編)

ここから本題。やり方としては最大表示文字数を変動させます。
DOText()をDOMaxVisibleCharacters()に置き換えるだけ。

    /// <summary>
    /// string型文字列を受け取ってTextに表示
    /// </summary>
    private void WriteText(string message)
    {
        currentTween?.Kill();
        text.text = message;
        text.maxVisibleCharacters = 0;
        text.ForceMeshUpdate();
        
        currentTween = text.DOMaxVisibleCharacters(message.Length, message.Length * writeTimePerChara).SetEase(Ease.Linear);
    }

 

コードを解説すると、
先に表示したい文字列を全てtextに流し込みForceMeshUpdate()で改行位置を確定させ。
後から最大表示文字数を0から増やしています。

 

実行してみるとこんな感じ。
途中で改行位置が変わることなく最後まで表示されます。

 

 

DOTween.Toを使ったやり方(無料版DOTween対応)

TextMeshProの拡張を使わないやり方も紹介します。
このコードなら無料版DOTweenでも機能します。

    /// <summary>
    /// string型文字列を受け取ってTextに表示
    /// </summary>
    private void WriteText(string message)
    {
        currentTween?.Kill();
        text.text = message;
        text.maxVisibleCharacters = 0;
        text.ForceMeshUpdate();

        // 0 から 文字数 まで値を変化させる
        currentTween = DOTween.To(
                () => text.maxVisibleCharacters,
                x => text.maxVisibleCharacters = x,
                message.Length,
                message.Length * writeTimePerChara
            ).SetEase(Ease.Linear);
    }

 

DOTween.To()で値のトゥイーンを行っています。
実行結果は同じ。

 

 

DOTextからの置き換え(UniTask版)

おまけにDOTweenを使わずUniTaskを使った書き方も紹介。
DOTweenを使わない・使いたくない方向け。

using TMPro;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Threading;
using Cysharp.Threading.Tasks;

public class TextTest_UniTask : MonoBehaviour
{
    [SerializeField] private TMP_Text text;
    [SerializeField] private Button button;
    [SerializeField] private string sentence;
    [SerializeField] private float writeTimePerChara = 0.1f;
    private CancellationTokenSource cts;
    
    private void Start()
    {
        button.onClick.AddListener(() => WriteTextAsync(sentence).Forget());
    }
    
    /// <summary>
    /// string型文字列を受け取ってTextに表示
    /// </summary>
    private async UniTaskVoid WriteTextAsync(string message)
    {
        cts?.Cancel();
        cts?.Dispose();
        cts = CancellationTokenSource.CreateLinkedTokenSource(this.GetCancellationTokenOnDestroy());
        
        text.text = message;
        text.ForceMeshUpdate();
        
        for (var i = 0; i <= message.Length; i++)
        {
            text.maxVisibleCharacters = i;
            var isCanceled = await UniTask.Delay(TimeSpan.FromSeconds(writeTimePerChara), cancellationToken: cts.Token)
                .SuppressCancellationThrow();
            if (isCanceled) return;
        }
    }
}

 

実行結果はだいたい同じ。

 

 

まとめ

今回はDOTextで日本語を表示する時に発生する、”途中で改行位置が変わる”現象を防ぐ方法をまとめました。
比較してみるとこんな感じ。

Unity製のゲームでそこそこ見かけるので、気になる人は試してみるといいかも。

 

 

以上です。

 

 

過去のUnity アドベントカレンダー記事

raspberly.hateblo.jp

raspberly.hateblo.jp

raspberly.hateblo.jp

raspberly.hateblo.jp