概要
以下で会話イベントについて記載してきました
…が、肝となるスクリプトの部分については
記載できていなかったので以下で記載していこうと思います!
あくまで私はこう実装しましたよっていうので参考までです
ScriptableObjectを使って会話文を表示してみよう
ScriptableObjectを使って
会話文を画面に表示するスクリプトを作成してみましょう!
ここで実装することは
画面をクリックしたら会話文を表示して
文字が流れていく。
で、文字が流れている最中にクリックしたら全文を表示。
で、全文が表示されている時にクリックしたら
次の文が流れていくという処理にしようと思います!
かつ、会話文の上には話し手の名前が表示されるようにしましょう
以下の画像のような感じです!
ではいきましょー!
全体像
まずは今回作成するものを以下に列挙します
・会話文を制御するメインのゲームオブジェクト
・会話文を表示するPanelとその子となるText
・会話文を表示するスクリプト
・会話文そのもののScriptableObject
会話文を制御するメインのゲームオブジェクトを追加
これは簡単なので説明するまでもないですが一応です
Hierarchyウィンドウ上で右クリック→Create Empty
で作成できます
で、作成したGameObjectの名前は「GameManager」にしました
(別に意味はありません)
会話文を表示するPanelとその子となるTextを追加
次にテキストを表示するオブジェクトを作成しましょう
Panelは背景、Textは会話文そのものです
PanelはHierarchyウィンドウ上で右クリック→UI→Panel
で作成できます
これでPanelが作成されます。
↓の赤枠がパネルです(ちょっと大きさを変更しています)
次にTextを作成しましょう
TextはPanelの中に表示したいので
Panelの子オブジェクトとして作成します
Hierarchyウィンドウ上のPanelで右クリック→UI→Text – TextMeshPro
をクリックします
するとText(TMP)という名前でテキストオブジェクトが作成されました
今回は話し手の名前と会話文の二つを画面に表示する必要があるため
もうひとつテキストを同じ手順で作成しましょう
私は以下のように
話し手のテキスト→SpeakerNameText
会話文のテキスト→dialogueText
としてテキストオブジェクトを作成しました
会話文を表示するスクリプトを作成
はい、ここが本題ですね!
やりたいことは以下です
・画面クリックで会話文が表示されていなければ
表示し1文字ずつ文章を表示していく
・会話文を表示中に画面クリックで会話文を全文表示する
・会話文が全文表示されている時に画面クリックで次の会話文を表示する
・全ての会話文の表示が終了してから画面クリックで
会話文のパネルを非表示にする
とりあえず会話文を表示だけするスクリプト
いきなり全部どんとスクリプトの内容を記載してもいいのですが
分かりにくくなると思うので
まずは画面に会話文を表示するだけの
スクリプト(GameControllerという名前にします)を
以下に記載します
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class GameController : MonoBehaviour
{
[SerializeField] private DialogueText dialogueText;
[SerializeField] private GameObject panelObject;
[SerializeField] private TextMeshProUGUI speakerNameText;
[SerializeField] private TextMeshProUGUI speakerDialogueText;
int index = 0;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// 会話文表示処理を実行する
displayDialogueText();
}
}
/// <summary>
/// 会話文表示処理
/// </summary>
public void displayDialogueText()
{
// パネルが非表示なら表示する
if (!panelObject.activeSelf)
{
panelObject.SetActive(true);
}
// scriptableObjectの情報をパネルに表示する
speakerNameText.text = dialogueText.speakerName;
if (dialogueText.paragraphs.Length > index)
{
speakerDialogueText.text = dialogueText.paragraphs[index];
} else
{
// 会話が終了したためパネルを非表示にする
speakerNameText.text = "";
speakerDialogueText.text = "";
panelObject.SetActive(false);
}
index++; //次の会話文インデックス
}
}
ここでは単純にupdate関数内で
マウスクリックしたら話し手の名前と会話文を表示します
必要なオブジェクトのアタッチについては以下に記載します
まずGameManagerオブジェクトに作成したGameControllerをアタッチしましょう
続いてGameControllerのDialogueTextに作成したScriptableObjectをアタッチします
「会話文を表示するPanelとその子となるTextを追加」で作成したパネルや
テキストのオブジェクトもアタッチしていきましょう
はい!これでゲーム開始したら以下のようになります!
会話文を1文字づつ表示するようにしてみよう!
では上記スクリプトを元に
1文字づつ画面に会話文を表示するようにしてみましょう!
こんな感じにスクリプト修正しました!
ハイライトした行が上記スクリプトから追加した行です
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class GameController : MonoBehaviour
{
[SerializeField] private DialogueText dialogueText;
[SerializeField] private GameObject panelObject;
[SerializeField] private TextMeshProUGUI speakerNameText;
[SerializeField] private TextMeshProUGUI speakerDialogueText;
int index = 0;
bool isTyping;
private Coroutine dialogueCoroutine;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// 会話文表示処理を実行する
displayDialogueText();
}
}
/// <summary>
/// 会話文表示処理
/// </summary>
public void displayDialogueText()
{
// パネルが非表示なら表示する
if (!panelObject.activeSelf)
{
panelObject.SetActive(true);
}
// scriptableObjectの情報をパネルに表示する
speakerNameText.text = dialogueText.speakerName;
if (dialogueText.paragraphs.Length > index)
{
if (!isTyping)
{
dialogueCoroutine = StartCoroutine(TypeDialogueText(dialogueText.paragraphs[index]));
} else
{
stopTyping();
}
} else
{
// 会話が終了したためパネルを非表示にする
speakerNameText.text = "";
speakerDialogueText.text = "";
panelObject.SetActive(false);
}
}
/// <summary>
/// ダイアログのテキストを一文字づつ表示していきます
/// </summary>
/// <param name="paragraph"></param>
/// <returns></returns>
private IEnumerator TypeDialogueText(string paragraph)
{
string displayText = "";
isTyping = true;
foreach(char c in paragraph)
{
displayText = displayText + c;
speakerDialogueText.text = displayText;
yield return new WaitForSeconds(0.05f); // タイピングのスピード
}
isTyping = false;
index++; //次の会話文インデックス
}
/// <summary>
/// 1文字づつ表示を終了しテキスト全文を表示する
/// </summary>
private void stopTyping()
{
StopCoroutine(dialogueCoroutine);
// 未表示の会話文を全文表示する
speakerDialogueText.text = dialogueText.paragraphs[index];
isTyping = false;
index++; //次の会話文インデックス
}
}
このスクリプトでゲームを開始したのが以下になります
タイピング中に急に改行されるのをなんとかしよう!
上記のスクリプトの問題点として
文字列を1文字づつ追加していることです
なぜそれが問題なのか以下をみると一目瞭然だと思います
いきなり文字が途中から改行されてしまいますね
これはちょっとダサいので修正しましょう!
どうするかというとTextMeshProのRich Textで解決します
表示する文字を追加していくのでなく
全ての文字列の色を透明にする
↓
タイピングしている文字を透明じゃなくする
これをするとそもそも文字は全文表示されているので(透明だけど)
タイピングの途中で改行されるということはなくなりますね
ということでこの修正を加えたスクリプトが以下です
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class GameController : MonoBehaviour
{
[SerializeField] private DialogueText dialogueText;
[SerializeField] private GameObject panelObject;
[SerializeField] private TextMeshProUGUI speakerNameText;
[SerializeField] private TextMeshProUGUI speakerDialogueText;
int index = 0;
bool isTyping;
private Coroutine dialogueCoroutine;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// 会話文表示処理を実行する
displayDialogueText();
}
}
/// <summary>
/// 会話文表示処理
/// </summary>
public void displayDialogueText()
{
// パネルが非表示なら表示する
if (!panelObject.activeSelf)
{
panelObject.SetActive(true);
}
// scriptableObjectの情報をパネルに表示する
speakerNameText.text = dialogueText.speakerName;
if (dialogueText.paragraphs.Length > index)
{
if (!isTyping)
{
dialogueCoroutine = StartCoroutine(TypeDialogueText(dialogueText.paragraphs[index]));
} else
{
stopTyping();
}
} else
{
// 会話が終了したためパネルを非表示にする
speakerNameText.text = "";
speakerDialogueText.text = "";
panelObject.SetActive(false);
}
}
/// <summary>
/// ダイアログのテキストを一文字づつ表示していきます
/// </summary>
/// <param name="paragraph">会話の1文</param>
/// <returns>IEnumerator</returns>
private IEnumerator TypeDialogueText(string paragraph)
{
string displayText = "";
isTyping = true;
int colorIndex = 0;
foreach(char c in paragraph)
{
colorIndex++;
speakerDialogueText.text = paragraph;
displayText = speakerDialogueText.text.Insert(colorIndex, "<color=#00000000>");
speakerDialogueText.text = displayText;
yield return new WaitForSeconds(0.05f);
}
isTyping = false;
index++; //次の会話文インデックス
}
/// <summary>
/// 1文字づつ表示を終了しテキスト全文を表示する
/// </summary>
private void stopTyping()
{
StopCoroutine(dialogueCoroutine);
// 未表示の会話文を全文表示する
speakerDialogueText.text = dialogueText.paragraphs[index];
isTyping = false;
index++; //次の会話文インデックス
}
}
これでゲーム実行してみたのが以下です
おわり!
簡単ではありますが画面に会話文っぽいやつを表示できるようになりました!
更に処理を追加していっていい感じのものにしていこうと思います!
どうでもいいですがこの記事書くのに3か月ぐらいかかりました…
やる気出なくてさぼったりしていました…長かった…
もうちょっと更新頻度高められるように頑張ります!!(多分!)