TextMeshProでテキストを一文字ずつ、文字送りする。

Unityでノベルゲームのような会話シーンを制作するとき、「文字を1文字ずつ表示したい!」ことがあると思います。
突然テキストが表示されるのではなく、まるでキャラクターが実際に話しているかのような演出があれば、プレイヤーの没入感も大きくアップさせることができます。
しかし、「実際にどうやって実装するの?」や「初心者でも簡単にできる方法はないの?」と悩んでいる方も多いでしょう。
本記事では、UnityのTextMeshPro(TMP)を使って1文字ずつ表示する方法を分かりやすく解説します。
具体的な実装例や注意点も挙げながら、初心者の方でも迷わず実践できる内容にしています。
- 文字を1文字ずつ流れるように表示する基本的な方法
- コルーチンを使った効率的で簡単な実装方法
- 応用として、途中で一気に全文を表示する方法
- 注意すべきポイントやトラブルシューティング
文字送り表示

文字送りとは、テキストが一瞬で表示されるのではなく、1文字ずつ流れるように表示されるアニメーションのことを指します。
これはノベルゲームやアドベンチャーゲームなど、キャラクター同士が会話をするシーンでよく用いられています。
1文字ずつ表示されることによって、キャラクターが実際に言葉を話しているかのような臨場感を出すことができます。
プレイヤーの没入感を高める重要な要素なので、ゲームのクオリティを上げたいならぜひマスターしましょう。
また、RPGやチュートリアル表示など、幅広いジャンルのゲームにも応用可能です。
コルーチンで実装
Unityで1文字ずつの表示を効率的かつ簡単に実現するためには、
「コルーチン(Coroutine)」を使用します。
コルーチンとは、特定の処理を途中で待機(一定時間停止)させたり、
少しずつ処理を実行したりできるUnity特有の便利な機能です。
似た機能にInvokeというものがありますが、Invokeは指定した関数を一度または定期的に呼び出すシンプルな仕組みであるのに対し、コルーチンは細かな処理の制御に適しています。
本記事のような単純に文字送りをするだけならInvokeでも良いですが、
文字送りの速度を微調整したり、特定の文字だけ遅らせたりする場合は、コルーチンをおすすめします。
コルーチンを使った1文字ずつ表示する

今回紹介する方法は、TextMeshPro(テキストメッシュプロ)を使って、
簡単に実装できるシンプルな方法です。
ソースコードの大まかな流れは以下の通りです。
- Resourcesフォルダに格納したテキストファイル(csv)を読み込み、表示するテキストを準備
- コルーチンを利用して1文字ずつ表示し、表示間隔を調整
- テキスト中のタグ(やなど)が途切れないように注意して処理
Unityでテキストを表示するのは多種ありますが、TextMeshProが主流です。
制御もしやすく、フォントを自由に使うことができます。
stringを使用してスクリプト内のテキストで表示させる方法もありますが、
本記事では扱いやすくてより実践的なCSVファイルを読み込んで表示します。
ソースコード
using System.Collections;
using UnityEngine;
using TMPro;
using System.IO;
public class typing : MonoBehaviour
{
public TextMeshProUGUI LogText;
public float typingInterval = 0.05f; // 文字表示の速度
private string fullText;
private bool isTyping = false;//タイピング開始
void Start()
{
LoadCSV("Sample");
}
void LoadCSV(string fileName)
{
TextAsset csvFile = Resources.Load<TextAsset>(fileName);
if (csvFile != null)
{
using (StringReader reader = new StringReader(csvFile.text))
{
fullText = reader.ReadLine();
}
StartCoroutine(TypeText());
}
else
{
Debug.LogError($"CSVファイル({fileName})が見つかりません。");
}
}
IEnumerator TypeText()
{
isTyping = true;
LogText.text = "";
int i = 0;
while (i < fullText.Length)
{
if (fullText[i] == '<') // タグ開始の処理
{
int tagEnd = fullText.IndexOf('>', i);
if (tagEnd != -1)
{
LogText.text += fullText.Substring(i, tagEnd - i + 1);
i = tagEnd + 1;
}
}
else
{
LogText.text += fullText[i];
i++;
yield return new WaitForSeconds(typingInterval);
}
}
isTyping = false;
}
}解説
- 名前空間
「System.Collections」:IEnumeratorとコルーチンを利用するために必要。
「UnityEngine」:MonoBehaviourを継承し、Unityの基本機能を使用するために必要。
「TMPro」:TextMeshProUGUIを使用し、UIにテキスト表示を行うために必要。
「System.IO」:文字列の読み込みや操作にStringReaderを使用するために必要。
- フィールド(メンバ変数)
「LogText」:画面に表示するテキスト(TMP)を格納し、逐次テキストを追加表示するためのUI要素。
「typingInterval」:1文字表示ごとの待機時間(秒数)を指定することで、テキスト表示の速度を調整する。
「fullText」:CSVファイルから読み込んだ表示対象の文字列を格納する。
「isTyping」:現在タイピング表示処理が進行中か否かを判定するフラグ(真偽値)。
- LoadCSVメソッド
引数として渡されたファイル名(Resources内にあるCSV形式のテキストファイル)を読み込む。
読み込みが成功すると、ファイルから取得した最初の行のテキストをfullTextに格納し、
TypeTextコルーチンを呼び出して文字列の逐次表示を開始する。
指定のファイルが存在しない場合は、エラーをログに表示する。
- TypeTextメソッド
コルーチンを用いて、fullTextに格納されているテキストを1文字ずつ表示する。
文字列内にHTMLタグなどの特殊タグ(<…>)があった場合はタグ全体をまとめて表示し、
タグが途切れないよう処理する。
タグではない通常の文字は、指定したインターバル(typingInterval)ごとに1文字ずつ追加表示される。
全ての文字を表示し終えると、isTypingフラグをfalseに戻し、処理を完了する。
実演
作成したスクリプトをInspectorウィンドウにアタッチして実行すると、
以下のような挙動を確認できます。
- Resourcesフォルダに配置されたCSVファイルの最初の行が1文字ずつゆっくりと表示される
- <color>や<size>などのTextMeshProタグは、文字送りの途中で途切れることなく正しく表示される
- テキスト表示中は他の入力を受け付けない(ただし、後述の応用機能で回避可能)
CSVはResourcesフォルダーに入れて管理しますが、現在は非推奨です。
文字送り中に、右クリックで全表示する
さらに快適なユーザー体験を提供するために、応用機能として「右クリックすると瞬時に全テキストが表示される機能」も追加してみましょう。
これによりプレイヤーが待ち時間を自由にコントロールでき、ストレスを軽減できます。
void Update()
{
if (Input.GetMouseButtonDown(1) && isTyping)
{
StopAllCoroutines();
LogText.text = fullText;
isTyping = false;
}
}右クリックでコルーチンを途中停止することで、処理の完了を即時化します。
左クリックで全文を表示し、もう一度で次の行へ進む
会話を読み進めるゲームでは、文字の表示中に左クリックすると全文が出て、もう一度左クリックすると次の行へ進む、という動きがよく使われます。
private Coroutine typingCoroutine; // 動いているコルーチンを覚えておく
void ShowLine(string text)
{
fullText = text;
if (typingCoroutine != null) StopCoroutine(typingCoroutine);
typingCoroutine = StartCoroutine(TypeText());
}
void Update()
{
if (!Input.GetMouseButtonDown(0)) return;
if (isTyping)
{
// 1回目のクリック:全文を表示するだけ
StopCoroutine(typingCoroutine);
LogText.text = fullText;
isTyping = false;
}
else
{
// 2回目のクリック:次の行へ
NextLine(); // 次の行の文字をShowLineに渡す処理
}
}StopAllCoroutines()は、そのスクリプトで動いているすべてのコルーチンを止めます。自動送りなど別のコルーチンも同じスクリプトで動かしている場合は、上のようにStartCoroutineの戻り値を覚えておき、StopCoroutineでそれだけを止めます。

左クリックで「全文表示→次の行」、右クリックでバックログを開く、という分け方にしています。オート再生も別のコルーチンで動かしているので、StopAllCoroutines()だとオートまで止まってしまいました。
閉じていない「<」でゲームが固まるのを防ぐ
本記事のTypeTextは、閉じていない「<」(「>」が無いもの)がセリフにあると、読む位置が進まずにゲームが固まります。タグの終わりが見つからないときは、「<」を普通の文字として1文字進める処理を足しておくと安全です。
if (tagEnd != -1)
{
LogText.text += fullText.Substring(i, tagEnd - i + 1); // タグはまとめて追加
i = tagEnd + 1;
}
else
{
LogText.text += fullText[i]; // 閉じていない < はそのまま表示
i++;
}まとめ
この記事では、UnityのTextMeshProを使った1文字ずつ表示する方法を解説しました。
キャラクターが実際に会話しているような演出を実現することで、
ゲームのクオリティやプレイヤーの没入感が大幅に向上します。
また、「右クリック即時表示」機能を導入すれば、
ユーザーがさらに快適にゲームを楽しめます。
次のステップとして以下の記事もチェックして、さらなるスキルアップを目指しましょう!







