【Unity】LESSON01. 一文字ずつ進むセリフの表示をして簡単にRPGチックなテキストボックスにしちゃおう！（解説付き）【★★★✩✩】

# 入力した文字列をRPGのセリフ表示っぽくしよう

**プログラミング初学者向きの記事となっています。**
「UnderTale」や「ゼルダの伝説」のセリフって文字が一文字一文字テキストボックスに追加されて行きますよね？それを出来るだけ簡単に実装して行きます！

# ①まずはUnity上での作業
## CanvasにTextを追加しよう(1/2)

まずは文字を表示させる為にGameObject→UI→Textの順番でクリックしていき「Text」を出しましょう！![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/64a3c166-3a86-7f20-0768-5be79b27bf74.png)

▼Canvas
  Text
↑みたいになります！

文字の大きさや、表示させたい位置を自分の好きな所に設定してね！

## Textにスクリプトをアタッチしよう！(2/2)

最初は「New Text」となってるはずなのでこれを変えます！Textに表示されてる文字列を変えるためのスクリプトの準備をします！

Projectのウィンドウで右クリック→Create→C# Scriptの順番に操作します！
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/3f038760-bfe2-3e22-017c-48e798b2c6c4.png)

そうするとスクリプトが生成されます。そのスクリプトに適当な名前をつけます。今回は「TextDisplay」としましょう！(Displayは表示という意味)

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/b7be888c-d2f4-a5f1-30f1-58599ef76924.png)

そうしたらTextDisplayスクリプトをTextにアタッチします。下の画像のどっちの操作でもアタッチできるので、好きな方のアタッチの方法でやってください！

アタッチ方法①
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/dd7f1b68-a9e1-1717-0ca8-a5d23bab576e.png)


アタッチ方法②
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/7ca8dbab-3524-d2c3-e122-9e729e48f629.png)


（アタッチ方法①,②のどちらかやればいいよ！）

結果的に下の画像のように表示されたらオッケーです！
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/45cc40f3-b145-8c53-1372-cb6667aec71a.png)


# ②つぎはプログラミングの作業
では、TextDisplayスクリプトを開いてプログラミングの作業を始めます！ひとつひとつの機能を一緒に理解しながら作って行きましょう。
**【注意！】プログラムに「 // 」←がついている行が新しい行です。その行を追加していってくださいね！**

## スクリプトから文字を手動で変える(1/5)
まずは簡単な方法で文字を変えます。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//←これを追加

public class TextDisplay : MonoBehaviour
{
    void Start()
    {
    }
    void Update()
    {
        this.GetComponent<Text>().text = "文字を変える";//画面上にdisplayTextを表示
    }
}
```

このプログラムを書くとUnity上で生成したTextの内容が 「 "" 」で挟まれた文字列の内容に変化します。![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/9603c0df-5fe7-efde-fa7a-dbbf4d196215.png)

この機能を主に使ってシステムを作って行きます。

## public変数を使ってUnityから文字入力(2/5)

次はstring型の変数を使って文字列の内容を変えます。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string texts;//変数宣言
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = texts;//←変える
    }
}
```

書いたらUnity上ではこのように表示されるはずなので、ここに文字列の内容を書いてみましょう。![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/731e6ee7-5a5c-9ff3-fb82-67f43cc1423f.png)

実行するとUnityで入力した文字列に変更されましたね？

## string型のpublic配列を作ろう(3/5)

次はtextsを変数ではなく配列として宣言しましょう。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;//←変える
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = texts[0];//←変える
    }
}
```

このように記述すると、文字列を複数個入力できるようになりますね？![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493679/e2728062-f68a-3a7e-7cac-552832917ddb.png)

そして実行すると0番目に入力した文字列が表示されるようになったはずです。なぜかというと、

```
this.GetComponent<Text>().text = texts[0];
```
の数の文字列を表示するプログラムになっているからです。ここの数字を変えれば文字列が順番に表示されるようになります。

## texts[0]←ここの数字を変数を使って増やしていく(4/5)

Unity上で入力した文字列の順番に変えていくプログラムを作ります。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;//追加
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = texts[textNumber];//←変える
        textNumber = textNumber + 1;//追加
    }
}
```
このように書くと内容が変わるようになりましたね？恐らくめちゃめちゃ速く。
このままだとまともにセリフが読めないので、クリックしたら変更するようにします。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = texts[textNumber];
        if (Input.GetMouseButtonDown(0))//追加
        {//追加
            textNumber = textNumber + 1;
        }//追加
    }
}
```

if文の条件をクリックしたら「(Input.GetMouseButtonDown(0))」にし、{}の中でtextNumberを1ずつ増やすプログラムにしました。これで好きなタイミングで変えることができるようになったはずです。

### 最後のセリフで止める
恐らく上のプログラムだと、クリックをし続けるとエラーが出てしまいますよね？それを防ぐプログラムを追加します。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = texts[textNumber];
        if (textNumber != texts.Length - 1)//追加
        {//追加
            if (Input.GetMouseButtonDown(0))
            {
                textNumber = textNumber + 1;
            }
        }//追加
    }
}
```

この様なif文を追加すると最後の文章で止まるようになります。具体的には、textNumberがtexts配列の数-1以外ならクリックしたらという条件を追加しました。

## 一文字ずつ表示させるプログラム(5/5)

次は一文字一文字表示させるプログラムですが、新たに二つの変数を追加で宣言します。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    string displayText;//追加
    int textCharNumber;//追加
    void Start()
    {

    }
    void Update()
    {
        this.GetComponent<Text>().text = displayText;//変更
        if (textNumber != texts.Length - 1)
        {
            if (Input.GetMouseButtonDown(0))
            {
                textNumber = textNumber + 1;
            }
        }
    }
}
```

今後はstring型の変数displayTextを表示させていくことにします。では、displayTextに文字データを一文字一文字プログラミングで入力していきましょう。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    string displayText;
    int textCharNumber;
    void Start()
    {

    }
    void Update()
    {
        if (textCharNumber != texts[textNumber].Length) //追加
        {//追加
            displayText = displayText + texts[textNumber][textCharNumber];//追加
            textCharNumber = textCharNumber + 1;//追加
        }//追加
        else//追加
        {//追加
            displayText = "";//追加
            textCharNumber = 0;//追加
        }//追加

        this.GetComponent<Text>().text = displayText;
        if (textNumber != texts.Length - 1)
        {
            if (Input.GetMouseButtonDown(0))
            {
                textNumber = textNumber + 1;
            }
        }
    }
}
```

```
displayText = displayText + texts[textNumber][textCharNumber];
```

この一行の説明をします。
変数**displayText**に**texts**配列の**textNumber**番目の文字列の**textCharNumber**番目の文字を追加するというプログラムです。

```
if (textCharNumber != texts[textNumber].Length) 
{
     textCharNumber = textCharNumber + 1;
}
```
このif文の意味は、もし**textCharNumber**が**texts**配列の**textNumber**番目の一つ前の数じゃなければ、textCharNumberを1ずつ増やすというプログラムです。
このif文のあとに

```
else
{
     displayText = "";
     textCharNumber = 0;
}
```
を追加すると、もし**textCharNumber**が**texts**配列の**textNumber**番目の一つ前の数のときに、**displayText**を""にしたり、**textCharNumber**を0に戻したりするというプログラムになります。
このプログラムのおかげで**textCharNumber**の数が文字列の数を超えた時バグらなくなります。

# ③今までのプログラムの統合

##一文字ずつ表示させて、クリックしたら次のセリフに移行するプログラム(1/1)

今までのプログラムを整理すると、

1. **displayText**に**texts**配列の**textNumber**番目の文字列の**textCharNumeber**番目の文字を最後の文字まで追加していく。
2. 最後の文字になった時に、追加する文字を最初にする。**displayText**を " " に戻す。
3. クリックされたら、次の**texts**配列を次の文字列にする。

という単純なプログラムです。
これの2と3を混ぜるだけでRPGチックになります。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    string displayText;
    int textCharNumber;
    void Start()
    {

    }
    void Update()
    {
        
        if (textCharNumber != texts[textNumber].Length) 
        {
            displayText = displayText + texts[textNumber][textCharNumber];
            textCharNumber = textCharNumber + 1;
        }
        else
        {
            if (textNumber != texts.Length - 1)
            {
                if (Input.GetMouseButtonDown(0))//移動
                {//移動
                    displayText = "";//移動
                    textCharNumber = 0;//移動
                    textNumber = textNumber + 1;//移動
                }//移動
            }            
        }

        this.GetComponent<Text>().text = displayText;
        
    }
}
```

うまくいきましたか？

# Ex
## 文字表記をゆっくりに(1/2)
文字表記をゆっくりにしたかったらこのようにすると文字のスピードが遅くなります。

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    string displayText;
    int textCharNumber;
    int displayTextSpeed;//追加
    bool click;//追加
    void Start()
    {

    }
    void Update()
    {
        displayTextSpeed++;
        if (displayTextSpeed % 5 == 0)//追加
        {//追加
            if (textCharNumber != texts[textNumber].Length)
            {
                displayText = displayText + texts[textNumber][textCharNumber];
                textCharNumber = textCharNumber + 1;
            }
            else
            {
                if (textNumber != texts.Length - 1)
                {
                    if (click==true)
                    {
                        displayText = "";
                        textCharNumber = 0;
                        textNumber = textNumber + 1;
                    }
                }
            }

            this.GetComponent<Text>().text = displayText;
            click = false;//追加
        }//追加
        if (Input.GetMouseButton(0))//追加
        {//追加
            click = true;//追加
        }//追加
    }
}
```

## 最後のセリフでクリックしたら消したい(2/2)

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;
    int textNumber;
    string displayText;
    int textCharNumber;
    int displayTextSpeed; 
    bool click;
    bool textStop;//追加
    void Start()
    {

    }
    void Update()
    {
        if (textStop == false)//追加
        {//追加
            displayTextSpeed++;
            if (displayTextSpeed % 5 == 0)
            {

                if (textCharNumber != texts[textNumber].Length)
                {
                    displayText = displayText + texts[textNumber][textCharNumber];
                    textCharNumber = textCharNumber + 1;
                }
                else
                {
                    if (textNumber != texts.Length - 1)
                    {
                        if (click == true)
                        {
                            displayText = "";
                            textCharNumber = 0;
                            textNumber = textNumber + 1;
                        }
                    }
                    else//追加
                    {//追加
                        if (click == true)//追加
                        {//追加
                            displayText = "";//追加
                            textCharNumber = 0;//追加
                            textStop = true;//追加
                        }//追加
                    }//追加
                }

                this.GetComponent<Text>().text = displayText;
                click = false;
            }
            if (Input.GetMouseButton(0))
            {
                click = true;
            }
        }//追加
    }
}
```
まず、**textStop**がfalseの時だけこのプログラムが動くようにプログラミングします。そして
もし最後のセリフの文字列になった時にクリックしたら、表示を " " にして**textStop**をtrueにすることで全てのプログラムを止められるようにします。
そうするとメッセージが止まったようになります。


# 最後に全体のプログラム

最後に全ての行に意味をコメントアウトで書いときます

```c#:TextDisplay.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextDisplay : MonoBehaviour
{
    public string[] texts;//Unity上で入力するstringの配列
    int textNumber;//何番目のtexts[]を表示させるか
    string displayText;//表示させるstring
    int textCharNumber;//何文字目をdisplayTextに追加するか
    int displayTextSpeed; //全体のフレームレートを落とす変数
    bool click;//クリック判定
    bool textStop; //テキスト表示を始めるか
    void Start()
    {

    }
    void Update()
    {
        if (textStop == false) //テキストを表示させるif文
        { 
            displayTextSpeed++;
            if (displayTextSpeed % 5 == 0)//５回に一回プログラムを実行するif文
            {

                if (textCharNumber != texts[textNumber].Length)//もしtext[textNumber]の文字列の文字が最後の文字じゃなければ
                {
                    displayText = displayText + texts[textNumber][textCharNumber];//displayTextに文字を追加していく
                    textCharNumber = textCharNumber + 1;//次の文字にする
                }
                else//もしtext[textNumber]の文字列の文字が最後の文字だったら
                {
                    if (textNumber != texts.Length - 1)//もしtexts[]が最後のセリフじゃないときは
                    {
                        if (click == true)//クリックされた判定
                        {
                            displayText = "";//表示させる文字列を消す
                            textCharNumber = 0;//文字の番号を最初にする
                            textNumber = textNumber + 1;//次のセリフにする
                        }
                    }
                    else //もしtexts[]が最後のセリフになったら
                    { 
                        if (click == true) //クリックされた判定
                        { 
                            displayText = ""; //表示させる文字列も消す
                            textCharNumber = 0; //文字の番号を最初にする
                            textStop = true; //セリフ表示を止める
                        } 
                    } 
                }

                this.GetComponent<Text>().text = displayText;//画面上にdisplayTextを表示
                click = false;//クリックされた判定を解除
            }
            if (Input.GetMouseButton(0))//マウスをクリックしたら
            {
                click = true; //クリックされた判定にする
            }
        } 
    }
}
```

あとは各々フォントなどをアレンジしてお好みのテキストボックスを作ってみてね！