ほぼ全てのゲームで見かけるメッセージボックスとクリック→次のメッセージを表示する仕様を纏めたいと思います。
メッセージボックスの配置
ゲーム画面は右の通りになります。下準備として以下の通り行います。
・スマホの縦画面相当の背景(720*1280)
・panelを画面下に配置(720*140)
・panel上に子としてbutton配置(560*140)
・image上に子としてtext2つ配置
buttonがメッセージボックスになりますが、最後のtext2つは人物名と本文の2種類になりますので、本文をRectTransformにて一段分下に下げて文字が重ならずに表示できる様にします。ちなみに文字サイズは28にしてますのでこのボックスには本文が約60文字入る仕様になっています。
文字送りの準備
人物名と本文のtext2つを配置しましたが、主人公が1人の場合心の声など人物名が要らないパターンもありますよね。両方のパターンを想定して以下新規スクリプトを作成します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class canvasUI : MonoBehaviour
{
public Text names, messages;//人物名と本文
public bool playing = false;
public bool onMassage = false;
void Update()
{
if (onMassage && playing){onMassage = false;}
}
public void onMessageButton()//次のページを表示させる用
{
onMassage = true;
}
public void DisplayMessage(string mes)//人物名不要用
{
names.text = "";
StartCoroutine("CoDrawText", mes);
}
public void DisplayMessage(string name, string mes)//通常会話用
{
names.text = name;
StartCoroutine("CoDrawText","「" + mes + "」");
}
IEnumerator CoDrawText(string mes)
{
playing = true;
float time = 0;
while (true)//無限ループ
{
yield return null;//毎フレーム実行
time += Time.deltaTime;
int len = Mathf.FloorToInt(time * 30);
if (len > mes.Length) break;//文字を満たすとループを抜ける
messages.text = mes.Substring(0, len);//(int 開始位置, int 長さ)
}
playing = false;
}
}
完成したらbuttonのクリックイベントにonMessageButtonメソッドを指定します。メッセージの中身は別スクリプト(クラス)でDisplayMessageメソッドを使用するのですが、ここで呼び出されるCoDrawTextコルーチンが文字送り処理になります。
このコルーチン内にはwhile (true)で無限ループを配置しており、指定された文字数(別途DisplayMessageメソッドで指定)を整数の変数であるlenが満たすと抜ける仕組みになっています。yield return nullはUpdateメソッドのようなもので毎フレーム実行されるのですが、Time.deltaTimeで秒数変換→さらにそれを30で乗算する事でlenをカウント→Substringでlenの長さまで文字送りしていきます。つまり1秒間で約30文字づつ文字送りできるという訳です。
文字送りの実行
では作成したcanvasUIクラスを基に実行していこうと思います。以下新規スクリプトを作成しましょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class TextManager : MonoBehaviour
{
public canvasUI ui;//canvasUIクラスを使用
public bool nowMessage = false;//メッセージ中に他操作をさせない為活用
void Start(){StartCoroutine("Introduction");}
IEnumerator Skip()//クリック待ちのコルーチン
{
while (ui.playing) yield return null;
while (!ui.onMassage) yield return null;
}
IEnumerator Introduction()//文章を表示させるコルーチン
{
nowMessage = true;
ui.DisplayMessage("・・・・・・・・・・");
yield return StartCoroutine("Skip");
ui.DisplayMessage("?", "う・・・寒っ・・・あれ?ここどこ?");
yield return StartCoroutine("Skip");
Instantiate(imagePrefabTejou, content);
ui.DisplayMessage("知らない部屋だ。・・・ドアには鍵がかかっている。手錠もされてるし監禁ってやつかな。");
yield return StartCoroutine("Skip");
ui.DisplayMessage("・・・思い出した。小学校の帰りに突然誰かに殴られたんだっけ。とりあえずドアの向こうに助けを求めてみるか。");
yield return StartCoroutine("Skip");
ui.DisplayMessage("?", "おーーーーい!!誰かいるーー?");
yield return StartCoroutine("Skip");
ui.DisplayMessage("怖そうな男の声", "うるせえぞ黙れ!!大人しくしねえと殺すぞ。");
yield return StartCoroutine("Skip");
ui.DisplayMessage("・・・この口調は犯人か。静かにしておこう。");
yield return StartCoroutine("Skip");
ui.DisplayMessage("聞き覚えのある声", "聞こえるかコウタ。静かにしてろ。");
yield return StartCoroutine("Skip");
ui.DisplayMessage("今度は幻聴かな。兄貴の声?");
yield return StartCoroutine("Skip");
ui.DisplayMessage("");
nowMessage = false;
}
}
2種類のDisplayMessageメソッドを活用しているのは見ての通りですが、Skipコルーチンでクリックしたら次のメッセージに進む処理を挟んでいます。このSkipコルーチンは playingフラグfalse(文字送り完了)→onMassageフラグtrue(メッセージボックスクリック)の二段構成ループ離脱になります。クリックでなく秒数で次のメッセージに進みたい場合は、Skipコルーチンの代わりにyield return new WaitForSeconds(1.0f);の処理を挟むと機能します*この場合は1秒後。
インスタント文字送りの実行
ノベルゲームは先程のやり方で良いのですが、アドベンチャーゲームなどで気になる所を多数クリックしていく場合はコードを書きまくってグチャグチャになりそうですよね。インスタント用としてTextManagerクラスに以下メソッドを追加しましょう。
public void Normalmessage(string normal)
{
if (!nowMessage)
{
StartCoroutine("normalmessage", normal);//コルーチンに引数を渡す
}
}
IEnumerator normalmessage(string normal)
{
nowMessage = true;
ui.DisplayMessage(normal);
yield return StartCoroutine("Skip");
ui.DisplayMessage("");
nowMessage = false;
}
Normalmessageメソッドは下のコルーチンに文字列を渡す構成になっているので、適当なボタンに設定してinspectorウィンドウで好きな文字を入力するだけで機能します。
まとめ
それぞれのデモになります。この処理さえ使えればゲー無はもう作れたも同然です。
コメント