5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】1文字ずつメッセージを表示する

Posted at

UNDERTAL●やどうぶつの●のようにキャラクターがしゃべる時のアレです。

コピペ用

そのままコピペしてプロジェクトのどこかにおいてください。

  • MessageText.cs
MessageText.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Text))]
public partial class MessageText : MonoBehaviour
{
    /// セリフ音
    public AudioClip audioClip;
    Button _parentButton;
    AudioSource _audioSource;
    Text _text;
    float _charIntervalSec = 0f;
    bool _isWriting = false;
    int _lineIndex = 0;
    List<Line> _allLines;
    List<char> _muteChars;
    virtual public float charIntervalSec { get => 0.02f; }

    public void Start()
    {
        _audioSource = gameObject.AddComponent<AudioSource>();
        _audioSource.playOnAwake = false;
        _audioSource.clip = audioClip;
        _text = GetComponent<Text>();
        _allLines = GetAllLines();
        _muteChars = GetMuteChars();
        _parentButton = transform.parent.gameObject.GetComponent<Button>();
        _parentButton?.onClick.AddListener(OnClickParentButton);
        ClearLines();
        OnAppear();
    }
}

public partial class MessageText
{
    virtual public List<Line> GetAllLines()
    {
        return new List<Line>() { };
    }
    virtual public List<char> GetMuteChars()
    {
        return new List<char>() { };
    }
    virtual public void OnAppear()
    {
        WriteLine();
    }
    virtual public void OnComplete()
    {
        Destroy(this.gameObject);
    }
    virtual public void OnClickParentButton()
    {
        PushAction();
    }

    public void WriteLine()
    {
        _charIntervalSec = charIntervalSec;
        StartCoroutine(IEWrite(_allLines[_lineIndex].text));
    }
    void ClearLines()
    {
        _text.text = "";
    }
    void makeNewLine()
    {
        var line = _allLines[_lineIndex];
        switch (line.lineType)
        {
            case LineType.SkipOn:
                _text.text += "\n";
                break;
            case LineType.SkipOff:
                _text.text += "\n";
                break;
            case LineType.Clear:
                break;
        }
        _lineIndex += 1;
    }
    void ReadNext()
    {
        makeNewLine();
        var line = _allLines[_lineIndex];
        switch (line.lineType)
        {
            case LineType.SkipOn:
                WriteLine();
                break;
            case LineType.SkipOff:
                WriteLine();
                break;
            case LineType.Clear:
                ClearLines();
                // 再帰呼び出し
                ReadNext();
                break;
        }
    }
    public void PushAction()
    {
        if (_allLines.Count - 1 <= _lineIndex)
        {
            OnComplete();
            return;
        }
        if (_isWriting)
        {
            if (_allLines[_lineIndex].lineType == LineType.SkipOn)
            {
                _charIntervalSec = 0f;
            }
        }
        else
        {
            ReadNext();
        }
    }
    System.Collections.IEnumerator IEWrite(string lineText)
    {
        _isWriting = true;
        foreach (char c in lineText)
        {
            _text.text += c;
            if (!_muteChars.Contains(c))
            {
                _audioSource.Play();
            }
            yield return new WaitForSeconds(_charIntervalSec);
        }
        _isWriting = false;
    }
}

public partial class MessageText
{
    public enum LineType
    {
        SkipOn,
        SkipOff,
        Clear,
    }
    public interface Line
    {
        LineType lineType { get; }
        String text { get; }
    }
    public class SkipOn : Line
    {
        public LineType lineType { get => LineType.SkipOn; }
        public String text { get; }
        public SkipOn(String text)
        {
            this.text = text;
        }
    }
    public class SkipOff : Line
    {
        public LineType lineType { get => LineType.SkipOff; }
        public String text { get; }
        public SkipOff(String text)
        {
            this.text = text;
        }
    }
    public class Clear : Line
    {
        public LineType lineType { get => LineType.Clear; }
        public String text { get => null; }
    }
}

使い方

Unityの画面で Button を作り、その子として自動生成される Text に以下のサンプル Sample.cs を貼り付けます。

Sample.cs
using System.Collections.Generic;

class Sample : MessageText
{

    // 文字と文字の間隔秒数 (短いほど早い)
    override public float charIntervalSec { get => 0.02f; }

    // 表示するメッセージ
    override public List<Line> GetAllLines()
    {
        // SkipOn: スキップできるテキスト
        // SkipOff: スキップできないテキスト
        // Clear: ここで文字を全部消す
        return new List<Line>()
        {
            new SkipOn("おはようございます、これは1番目のメッセージです"),
            new SkipOn("こんにちは、これは2番目のメッセージです"),
            new Clear(),
            new SkipOff("こんばんは、これは3番目のメッセージです"),
            new SkipOn("おやすみなさい、これは4番目のメッセージです"),
            new SkipOn("これでメッセージの表示を終わります"),
        };
    }

    // 音を出さない文字
    override public List<char> GetMuteChars()
    {
        return new List<char>()
        {
           ' ', ' ', ',' , '、', '。', '「', '」', '!', '?',
        };
    }

    // 表示されたとき
    override public void OnAppear()
    {
        // 最初の1行を書き始める
        WriteLine();
    }

    // 最後のメッセージ表示した後 (クリック後)
    override public void OnComplete()
    {
        // 自分を削除
        Destroy(this.gameObject);
    }

    // 親ボタンをクリックした時
    override public void OnClickParentButton()
    {
        // アクションを進める
        PushAction();
    }
}
  • この時点でゲームスタートすれば動きます。
  • サンプルの中身は好きなように変更してください。
  • Unityのインスペクタから Text を見ると音源をはめ込むところがあります。ここにセリフ音(mp3もしくはwavファイル)を設定してください。
  • 画像やテキストの見た目も通常通りボタンの画像やテキストを変更すればOKです。

今回は以上です。ありがとうございました。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?