今回はUnityで作ったメッセージ表示機能に選択肢を選び、その後のメッセージを変更したり、アイテムを与えたりといった機能を作りたいと思います。
メッセージ表示機能は以前作成したものを改良して使います。
メッセージ表示機能のUI部分はそのまま使いますので、以下の記事を参照しUIを作成してください。
最初に書いておきますが、使いやすくはないと思います。(^_^;)
今回の機能を作成すると以下のようなものが出来上がります。
選択ウインドウの作成
メッセージ表示機能のUIは既に出来ていると思いますので、次は選択肢を選択する時のUIを作成していきます。
ヒエラルキーのMessageUIゲームオブジェクトを選択し、右クリックからUI→Panelを選択して名前をChoiceWindowとします。
シーンビューでShiftキーとAltキーを押しながら四隅の△を操作し、以下のようなサイズに調整します。
次にChoiceWindowを選択し、インスペクタのAdd ComponentからLayout→Vertical Layout Groupを選択して取り付けます。
これは選択ウインドウの子に配置したUI要素を縦に並べる為に使用します。
Child AlignmentをMiddle Centerにし、子のUI要素を真ん中に整列するようにします。
Control Child SizeのWidthとHeightにチェックを入れ、UI要素の幅と高さがChoiceWindowのサイズによってコントロールされるようにします。
Child Force ExpandのWidthとHeightにチェックを入れ、UI要素を強制的に幅と高さの拡張します。
次にヒエラルキーのChoiceWindowを選択し右クリックからUI→Legacy→Textを選択し、名前をTitleとします。
(注)今回は古いTextコンポーネントを使いますが、TextMeshProを使う場合はそれ用にスクリプトを書き替えてください。
さらにChoiceWindowを選択し、右クリックからUI→Panelを選択します。
ヒエラルキーのChoiceWindowの子のPanelを選択し、インスペクタのAdd ComponentからLayout→Horizontal Layout Groupを選択し取り付けます。
これはPanelの子に配置する選択ボタンを横に整列させる為に使用します。
Spacingを20にし、Panelの子のUIの間隔を20にします。
Child AlignmentをMiddle Centerにし、Panelの子のボタンを真ん中に寄せます。
次にヒエラルキーのPanelを選択し、右クリックからUI→Legacy→Buttonを選択し、名前をYesButtonとします(以下の画像ではYesButton(Legacy)となってますが気にしないでください)。
YesButtonを選択し、インスペクタでWidthを100、Heightを30とします。
ヒエラルキーのYesButtonを選択し、Ctrl+Dキーを押して複製し、F2キーを押して名前をNoButtonとします。
ここまででヒエラルキーは以下のようになります。
またシーンビューでは以下のようになります。
YesButtonとNoButtonの子のTextに「はい」と「いいえ」を入力していますが、これは後でスクリプトから書き換えるので別に入力しなくてもいいです。
メッセージ表示機能スクリプトの改造
この記事の最初に紹介した記事内で作成したメッセージ表示機能のスクリプトを改造し、選択肢を選択する機能にも対応していきます。
新しくSelectionMessageスクリプトを作成し、MessageUIゲームオブジェクトに取り付けます。
以前に作成したMessageスクリプトが取り付けられている場合は削除してください。
ちょっとスクリプトが長いですし、重複する部分もありますが解説していきます。(^_^;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Text.RegularExpressions; using System.Collections.Generic; public class SelectionMessage : MonoBehaviour { // メッセージUI private Text messageText; // 最初に表示するメッセージ private string message = ""; // 「はい」を選択した時に最初に表示するメッセージ private List<string> stringWhenYesIsSelectedList = new List<string>(); // 「いいえ」を選択した時に最初に表示するメッセージ private List<string> stringWhenNoIsSelectedList = new List<string>(); // 使用する分割文字列 [SerializeField] private string splitString = "<>"; // 分割したメッセージ private string[] splitMessage; // 分割したメッセージの何番目か private int messageNum; // テキスト表示の間隔 [SerializeField] private float textDisplayInterval = 0.05f; // 経過時間 private float elapsedTime = 0f; // 今見ている文字番号 private int nowTextNum = 0; // マウスクリックを促すアイコン private Image clickIcon; // クリックアイコンの点滅秒数 [SerializeField] private float clickFlashTime = 0.2f; // 1回分のメッセージを表示したかどうか private bool isOneMessage = false; // メッセージがあるかどうか private bool hasMessage; // メッセージウインドウ [SerializeField] private GameObject messageWindow; // 選択肢ウインドウ [SerializeField] private GameObject choiceWindow; // 現在の文字列番号 private int numOfSelections; // 選択UIのテキスト [SerializeField] private Text choiceTitleText; [SerializeField] private Text yesButtonText; [SerializeField] private Text noButtonText; // 選択時にUIに表示するテキスト private List<string> titleTextList = new List<string>(); private List<string> yesTitleTextList = new List<string>(); private List<string> noTitleTextList = new List<string>(); private List<string> yesItemList = new List<string>(); private List<string> noItemList = new List<string>(); private bool choosing; void Awake() { clickIcon = transform.Find("Panel/Image").GetComponent<Image>(); messageText = GetComponentInChildren<Text>(); Initialize(); } void Update() { // メッセージがない、もしくは選択中はこれ以降何もしない if (!hasMessage || choosing) { return; } // 1回に表示するメッセージを表示していない if (!isOneMessage) { // テキスト表示時間を経過したらメッセージを追加 if (elapsedTime >= textDisplayInterval) { messageText.text += splitMessage[messageNum][nowTextNum]; nowTextNum++; elapsedTime = 0f; // メッセージを全部表示、または行数が最大数表示された if (nowTextNum >= splitMessage[messageNum].Length) { isOneMessage = true; } } elapsedTime += Time.deltaTime; // メッセージ表示中にマウスの左ボタンを押したら一括表示 if (Input.GetMouseButtonDown(0)) { // ここまでに表示しているテキストに残りのメッセージを足す messageText.text += splitMessage[messageNum].Substring(nowTextNum); isOneMessage = true; } // 1回に表示するメッセージを表示した } else { elapsedTime += Time.deltaTime; // クリックアイコンを点滅する時間を超えた時、反転させる if (elapsedTime >= clickFlashTime) { clickIcon.enabled = !clickIcon.enabled; elapsedTime = 0f; } // 現在のメッセージの次が最後のメッセージであり、かつ最後のメッセージが空文字の場合 if (messageNum + 1 >= splitMessage.Length - 1 && splitMessage[splitMessage.Length - 1] == "") { DisplayTheChoiceWindow(); } // マウスクリックされたら次の文字表示処理 if (Input.GetMouseButtonDown(0)) { nowTextNum = 0; messageNum++; clickIcon.enabled = false; elapsedTime = 0f; isOneMessage = false; // メッセージが全部表示されていたら終了 if (messageNum >= splitMessage.Length) { Initialize(); } else { messageText.text = ""; } } } } // 新しいメッセージを設定 public void SetMessage(string message) { this.message = message; // 分割文字列で一回に表示するメッセージを分割する splitMessage = Regex.Split(this.message, @"\s*" + splitString + @"\s*"); nowTextNum = 0; messageNum = 0; messageText.text = ""; isOneMessage = false; hasMessage = true; messageWindow.SetActive(true); } // 選択ボタンを押した時に実行 public void OnPushButton(bool onPush) { // 選択肢ウインドウを非表示にする choosing = false; choiceWindow.SetActive(false); // 押されたボタンに応じて次に表示するメッセージを変える if (onPush) { SetMessage(stringWhenYesIsSelectedList[numOfSelections]); if (yesItemList[numOfSelections] != "") { Debug.Log(yesItemList[numOfSelections] + "を取得"); } } else { SetMessage(stringWhenNoIsSelectedList[numOfSelections]); if (noItemList[numOfSelections] != "") { Debug.Log(noItemList[numOfSelections] + "を取得"); } } numOfSelections++; } // 選択肢に表示するテキストの設定 public void SetTheTitleTextOfTheChoice(List<string> stringWhenYesIsSelectedList, List<string> stringWhenNoIsSelected, List<string> choiceTitleList, List<string> yesTitleList, List<string> noTitleList, List<string> yesItemList, List<string> noItemList) { Initialize(); this.stringWhenYesIsSelectedList = stringWhenYesIsSelectedList; this.stringWhenNoIsSelectedList = stringWhenNoIsSelected; this.titleTextList = choiceTitleList; this.yesTitleTextList = yesTitleList; this.noTitleTextList = noTitleList; this.yesItemList = yesItemList; this.noItemList = noItemList; } // 選択肢ウインドウの表示 public void DisplayTheChoiceWindow() { choiceTitleText.text = titleTextList[numOfSelections]; yesButtonText.text = yesTitleTextList[numOfSelections]; noButtonText.text = noTitleTextList[numOfSelections]; choosing = true; choiceWindow.SetActive(true); } // 設定の初期化 public void Initialize() { clickIcon.enabled = false; stringWhenYesIsSelectedList.Clear(); stringWhenNoIsSelectedList.Clear(); titleTextList.Clear(); yesTitleTextList.Clear(); noTitleTextList.Clear(); yesItemList.Clear(); noItemList.Clear(); hasMessage = false; messageText.text = ""; messageWindow.SetActive(false); numOfSelections = 0; choosing = false; choiceWindow.SetActive(false); } } |
messageTextはメッセージを表示するUIのテキストです。
messageは表示するメッセージです。
stringWhenYesIsSelectedListは選択肢で「はい」側のボタンを押した時に表示するリストです。
stringWhenNoIsSelectedListは選択肢で「いいえ」側のボタンを押した時に表示するリストです。
splitStringはメッセージを分割する時に使用する区切り文字です。
splitMessageは分割したメッセージを入れる文字列の配列です。
messageNumは分割したメッセージの何番目かを表します。
textDisplayIntervalは一文字を表示するまでの時間です。
elapsedTimeは前回の文字を表示してからの経過時間です。
nowTextNumはメッセージ中の今何文字目を見ているかの番号です。
clickIconは次のメッセージの表示を促すアイコンです。
clickFlashTimeはアイコンの点滅間隔です。
isOneMessageは1回分のメッセージを表示したかどうかです。
hasMessageは表示するべきメッセージがあるかどうかです。
messageWindowはMessageUIの子のPanelをヒエラルキーで設定します。
choiceWindowはChoiceWindowをヒエラルキーで設定します。
numOfSelectionsは選択を何回したかどうかです。
choiceTitleTextは選択ウインドウのタイトルのテキストをインスペクタで設定します。
yesButtonTextは選択ウインドウの「はい」側のボタンの子のテキストをインスペクタで設定します。
noButtonTextは選択ウインドウの「いいえ」側のボタンの子のテキストをインスペクタで設定します。
titleTextListは選択ウインドウが開いた時に選択肢のタイトルのテキストに表示する文字列のリストです。
yesTitleTextListは選択ウインドウが開いた時に選択ウインドウの「はい」側のボタンの子のテキストに表示する文字列のリストです。
noTitleTextListは選択ウインドウが開いた時に選択ウインドウの「いいえ」側のボタンの子のテキストに表示する文字列のリストです。
yesItemListは選択ウインドウで「はい」側のボタンを押した時にアイテムが得られる場合のアイテムのリストです。
noItemListは選択ウインドウで「いいえ」側のボタンを押した時にアイテムが得られる場合のアイテムのリストです。
choosingは今現在選択ウインドウが開いて選択肢のボタンを押す状態にいるかどうかです。
AwakeメソッドではclicIconに自身のゲームオブジェクトの子のPanel、その子のImageを取得し、そこからImageコンポーネントを取得し入れています。
messageTextには自身の子からTextコンポーネントを探し入れています。
Initializeメソッドを呼び出して初期化しています。
Initializeメソッドは後で作成します。
今回はメッセージ等を他のゲームオブジェクトのStartメソッドで設定する予定なので、それよりも前に初期化したい為にSelectionMessageスクリプトではStartメソッドではなくAwakeメソッドを使っています。
通常であれば会話等が発生する時にメッセージを設定するのでStartメソッドでも構いませんが、今回は問題があるのでAwakeを使っています。
Updateメソッドでは!hasMessageで表示するメッセージがない場合、またはchoosingがtrue、つまり選択状態にある時はこれ以降の処理をしません。
!isOneMessageでまだ表示するメッセージがある場合はテキストを表示するインターバル時間を経過時間が越えていた場合にメッセージを表示しています。
マウスの左ボタンが押された時は一気にメッセージを表示します。
!isOneMessageがfalseの時は1回に表示するメッセージを表示しているので、クリックアイコンを点滅します。
ここら辺は最初の記事と同じなので詳細はそちらを参照してください。
現在のメッセージが最後のメッセージの前のメッセージであり、かつ最後のメッセージが空文字の場合にDisplayTheChoiceWindowメソッドを呼んで選択ウインドウを表示します。
今回の場合はメッセージの最後が空文字である場合に選択ウインドウを表示する仕様にしています。
なので例えば
1 2 3 | message = "おはよう<>こんにちは<>"; |
となっていれば「おはよう」のメッセージを表示し、マウスの左ボタンを押したら「こんにちは」のメッセージを表示し、「こんにちは」のメッセージを表示し終わったら選択ウインドウを開くという事になります。
選択ウインドウを開きたくない場合は文字列の最後の<>という記号を取り除きます。
1 2 3 | message = "おはよう<>こんにちは"; |
マウスの左ボタンを押した時は次のメッセージを表示します。
分割されたメッセージの最後であればInitializeメソッドを呼んで初期化しています。
SetMessageメソッドはメッセージを設定するメソッドです。
メッセージが設定されたらメッセージウインドウを表示します。
OnPushButtonメソッドはボタンが押された時に実行するメソッドで引数でbool値を受け取り、trueかfalseかで処理を分岐します。
ボタンが押されたのでchoosingをfalseにし、選択ウインドウを非表示にします。
「はい」側のボタンが押されたら「はい」側のボタンが押された時に表示するメッセージを新しいメッセージとして設定します。
また「はい」を選択した時に得られるアイテムがあるならばアイテム取得処理を実行します。
今回の場合は文字列リストでどのアイテムが得られるかという文字情報だけをコンソールに表示していますが、List<Item>のように書き換えて実際にアイテム数を変更するような処理に変える事が出来ます。
「いいえ」側のボタンが押されたら「いいえ」側のボタンが押された時に表示するメッセージを新しいメッセージとして設定します。
ボタンが押されたらいずれにしてもnumOfSelectionsをインクリメントし、メッセージや選択ウインドウのUIのテキスト、選択した時に得られるアイテム等のリストの番号を変えます。
SetTheTitleTextOfTheChoiceメソッドでは最初にInitializeメソッドで初期化処理をし、他のスクリプトからメッセージ表示機能で使うリストを受け取りフィールドに設定します。
引数に渡すリストは別のスクリプトで作成します。
DisplayTheChoiceWindowメソッドでは選択肢の順番に応じて選択ウインドウで使っているテキストを書き換え、choosingをtrueにして選択状態にし、選択ウインドウを開きます。
Initializeメソッドではこのシステムでの初期化を行っています。
メッセージ表示機能にメッセージを渡すスクリプトの作成
次にテストのためにメッセージ表示機能にメッセージリストを渡すスクリプトを作成します。
ヒエラルキーで右クリックからCreate Emptyを選択し、名前をSetMessageとします。
SetMessageゲームオブジェクトに新しくSetMessageScriptスクリプトを作成し取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class SetMessageScript : MonoBehaviour { [SerializeField] private SelectionMessage selectionMessage; // 表示するメッセージ private string message = "ああああああああ\nああああああああ<>メッセージ<>「はい」か「いいえ」を選択してね。<>"; // 「はい」を選択した時に表示するメッセージリスト private List<string> stringWhenYesIsSelectedList = new List<string> { "はいを選択した。<>", "歩くを選択した", "Aを選択した。" }; // 「いいえ」を選択した時に表示するメッセージリスト private List<string> stringWhenNoIsSelectedList = new List<string> { "いいえを選択した。次はどちらを選択しますか?<>", "走るを選択した。<>最後にどちらを選択しますか?<>", "Bを選択した。" }; // 選択肢タイトルリスト private List<string> titleTextList = new List<string> { "選択してね1", "選択してね2", "選択してね3" }; // 「はい」のボタンに表示するテキストリスト private List<string> yesTitleTextList = new List<string> { "はい", "歩く", "A" }; // 「いいえ」のボタンに表示するテキストリスト private List<string> noTitleTextList = new List<string> { "いいえ", "走る", "B" }; // 「はい」を選択した時に得られるアイテムリスト private List<string> yesItemList = new List<string> { "やくそう", "", "A" }; // 「いいえ」を選択した時に得られるアイテムリスト private List<string> noItemList = new List<string> { "", "どくけしそう", "B" }; // Start is called before the first frame update void Start() { // 適当に表示するテキストを設定する selectionMessage.SetTheTitleTextOfTheChoice(stringWhenYesIsSelectedList, stringWhenNoIsSelectedList, titleTextList, yesTitleTextList, noTitleTextList, yesItemList, noItemList); selectionMessage.SetMessage(message); } private void Update() { // マウスの右クリックをしたらテストのために会話リストを新しくして試す if (Input.GetMouseButtonDown(1)) { message = "追加テスト<>"; stringWhenYesIsSelectedList = new List<string> { "はいを選択<>", "次はどっち<>", "はい"}; stringWhenNoIsSelectedList = new List<string> { "いいえを選択<>", "次はどっち<>", "いいえ" }; titleTextList = new List<string> { "選択してね1", "選択してね2", "選択してね3" }; yesTitleTextList = new List<string> { "はい", "はい", "はい" }; noTitleTextList = new List<string> { "いいえ", "いいえ", "いいえ" }; yesItemList = new List<string> { "やくそう", "", "A" }; noItemList = new List<string> { "", "どくけしそう", "B" }; selectionMessage.SetTheTitleTextOfTheChoice(stringWhenYesIsSelectedList, stringWhenNoIsSelectedList, titleTextList, yesTitleTextList, noTitleTextList, yesItemList, noItemList); selectionMessage.SetMessage(message); } } } |
messageは最初のメッセージのリストです。
<>があると一度マウスクリックする必要があります。
文字列の最後に<>がある場合は選択ウインドウを開きます。
文字列の最後に<>の記号がない場合はメッセージの終了なのでメッセージウインドウを閉じます。
stringWhenYesIsSelectedListは選択肢で「はい」側のボタンを押した時に表示するメッセージリストです。
stringWhenNoIsSelectedListは選択肢で「いいえ」側のボタンを押した時に表示するメッセージリストです。
titleTextListは選択ウインドウの選択のタイトルのリストです。
yesTitleTextListは「はい」側のボタンに表示する文字列のリストです。
noTitleTextListは「いいえ」側のボタンに表示する文字列のリストです。
yesItemListは「はい」側のボタンを押した時にアイテムを付与したい時のアイテムのリストです。
noItemListは「いいえ」側のボタンを押した時にアイテムを付与したい時のアイテムリストです。
アイテムのリストでアイテムを付与しない場合はそこを空文字にしておきます。
Startメソッドでは作成したリスト群をSelectionMessageスクリプトのSetTheTitleTextOfTheChoiceメソッドを使って渡しています。
最初に表示するメッセージはSetMessageメソッドで渡します。
他のメッセージを表示したい時のテストをする為にUpdateメソッドでマウスの右ボタンを押した時に新しいリストを作成し、再度メッセージを設定出来るようにしています。
通常であればメッセージを表示したいタイミングでメッセージリストをSelectionMessageスクリプトに設定するようにします。
ちょっと使いづらいかも!?
今回作成したい選択ウインドウを含めたメッセージ表示機能だと個々のリストの数は<>記号が文字列の最後にない場合以外はリストに同じ数だけの要素が必要になります。
リストの要素の数が違う場合はエラーで止まります。
また選択肢で選択した後にstringWhenYesIsSelectedListとstringWhenNoIsSelectedListのメッセージを表示して表示するメッセージを変える事が出来ますが、その後、文字列の最後に<>がきて再度選択ウインドウを開いた時に以前の「はい」「いいえ」の選択にかかわらず次の選択肢のタイトル、「はい」側のボタンのテキスト、「いいえ」側のボタンのテキストは同じ物が表示されます。
なので
「はい」を押す、「はい」側のメッセージ、次の「はい」側の選択肢、という流れには出来ません。
「はい」を押す、「はい」側のメッセージ、次の共通の選択肢という流れになります。
終わりに
複雑に分岐したメッセージ機能にする場合は今回の機能は使い勝手は良くありません。
そういう場合はメッセージの表示が終わった時に選択肢のタイトル、「はい」側のボタンテキスト、「いいえ」側のボタンテキストを渡し、選択し終わったら表示するメッセージを渡し、と逐一メッセージを渡していくやり方がいいかもしれません。