【Unity】RPGを作るチュートリアルその48 メッセージウィンドウの制御クラス

【Unity】RPGを作るチュートリアルその48 メッセージウィンドウの制御クラス

シンプルなRPGをUnityで作るチュートリアルシリーズの48回目です。

第47回ではメッセージウィンドウに関する実装として、戦闘中のメッセージ定義を先に実装しました。

今回はメッセージウィンドウ内のUIと、ウィンドウ全体を制御するクラスを作成していきます。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

シンプルなRPGを作る上でどんな作業が必要か、どんな順番で作っていくと良さそうか、別ページで検討しました。基本的にこの流れに沿って進めていきます。

 

チュートリアルの一覧

このシリーズ全体の一覧は以下のページにまとめています。

 

前回の内容

前回はメッセージウィンドウに関する実装として、戦闘中のメッセージ定義を先に実装しました。

 

UIを制御するクラス

戦闘画面のUIとして、5つのグループを作成しました。

  • ステータス表示のUI
  • 敵キャラクターの名前表示のUI
  • コマンドのUI
  • 選択ウィンドウのUI
  • メッセージ表示のUI ◀︎今回はここ

これらのUIに関しては、ひとつのまとまりをウィンドウとみなして、そのウィンドウ自体を制御するクラスと、ウィンドウ内のUIを制御するクラスの2つをセットにして実装していきます。

今回はメッセージ表示のUIを作っていく際に必要になる、戦闘に関するメッセージの定義クラスを作っていきましょう。

 

メッセージウィンドウのUIを制御するクラス

メッセージウィンドウのUIを制御するクラスを作っていきます。このクラスで実装したいのは、

  • メッセージウィンドウのテキストへの参照を保持するフィールド
  • ページ送りカーソルへの参照を保持するフィールド
  • メッセージをクリアするメソッド
  • 表示する文字列を追加するメソッド
  • UIを表示するメソッド
  • UIを非表示にするメソッド

です。下2つは前回作成した「IBattleUIController」のインタフェースによって実装が強制されます。

基本的は引数で渡された文字列をメッセージウィンドウにセットしていくのが担当範囲です。

Projectウィンドウから「Assets/Scripts/Battle/UI」のフォルダを開き、MonoBehaviourのスクリプトを作成します。名前は [MessageUIController] にしました。

スクリプトファイルの作成
スクリプトファイルの作成

 

作成した「MessageUIController」の中身は以下のように記載しました。

メッセージウィンドウ内の操作が必要なUIパーツはテキスト部分とカーソルの画像なので、それらに対する参照用フィールドを作成しています。また、「_currentMessage」では現在表示中の文字列を保持して、ここに文字列を追加して表示できるようにしています。

例えば攻撃のメッセージなら、1行目に「〇〇の攻撃!」と表示して、後から2行目に「〇〇に〇〇のダメージ!」と追加で表示します。元となるメッセージを保持しつつ、時間をずらして表示するケースに備えて、現在表示中の文字列を保持するようにしています。

ClearMessage()のメソッドではTextMesh Proのテキストと、一時保持のフィールドの値をクリアしています。

AppendMessage()のメソッドではテキストの追加を行います。現在表示中のテキストがなければそのまま、表示中のものがあればそこに改行を入れた上で追加するようにします。

ShowCursor()とHideCursor()ではカーソル画像の表示/非表示を切り替えています。

 

メッセージウィンドウを制御するクラス

メッセージウィンドウを制御するクラスを作っていきます。このクラスで実装したいのは、

  • UI制御のクラスへの参照を保持するフィールド
  • セットアップするためのメソッド
  • テキスト生成する各種メソッド
  • テキストをセットするメソッド
  • ウィンドウを表示するメソッド
  • ウィンドウを非表示にするメソッド

です。セットアップするメソッドと、下2つの合計3つのメソッドは前回作成した「IBattleWindowController」のインタフェースによって実装が強制されます。

同じくProjectウィンドウの「Assets/Scripts/Battle/UI」のフォルダにて、MonoBehaviourのスクリプトを作成します。名前は [MessageWindowController] にしました。

スクリプトファイルの作成
スクリプトファイルの作成

 

作成した「EnemyNameWindowController」の中身は以下のように記載しました。

フィールドとしては、UIを制御するクラスへの参照をInspectorウィンドウからアサインするのに加えて、メッセージ表示の間隔についても設定できるようにしています。ここではデフォルト値として1秒にしていますが、お好みに合わせて変更していただければと思います。

「Generate〇〇」のメソッドでは、場面に対応する文字列を生成して、メッセージをセットするためのコルーチンを起動するようにしています。ShowMessageAutoProcess()のコルーチンではメッセージ表示の間隔として設定した時間が経過した後、「BattleManager」にメッセージ表示が完了したことを通知するようにします。この通知用メソッドについては、この後作成していきましょう。

ShowMessageAutoProcess()のコルーチンについては、メッセージ表示の間隔を別で渡せるようにオーバーロードも作成してあります。戦闘開始時のメッセージについては戦闘中のメッセージの表示間隔と変えたかったため、引数として時間間隔を渡せるものを用意しました。

 

既存のクラスの修正

新しく作ったクラスと繋ぎ合わせるため、既存のクラスも修正していきます。対象は、

  • BattleWindowManager
  • BattleStarter
  • BattleManager

です。

 

BattleWindowManagerの修正

ウィンドウを制御するクラスを追加したので、ウィンドウの管理クラスを修正していきましょう。修正したいポイントは、

  • フィールドの追加
  • リストに追加するコントローラの追加
  • 参照を取得するメソッドの追加

です。

 

BattleStarterの修正

続いて「BattleStarter」も修正していきます。修正したいポイントは、

  • 敵出現時のメッセージ表示時間のフィールドを追加
  • テスト用にコマンド入力フェーズに切り替えていた部分を削除
  • ShowEnemyAppearMessage()の処理を追加

です。

フィールドとして、戦闘開始のメッセージを表示する時間の「_startMessageTime」を追加しました。

 

StartBattle()のメソッドではテスト用にコマンド入力に切り替えていた部分を削除しました。

 

メッセージ表示のメソッドとして作成してあったShowEnemyAppearMessage()について、処理内容を追加しました。「BattleManager」が保持している敵キャラクターのIDを取得し、そこから敵キャラクターの定義データを取得、名前を使ってメッセージ生成を行い、メッセージウィンドウに表示しています。

表示後は「BattleManager」の方に通知がいくので、そちらでフェーズの切り替え処理を呼ぶようにします。

 

BattleManagerの修正

続いて「BattleManager」も修正していきます。修正したいポイントは、

  • StartBattle()でメッセージウィンドウを初期化する処理を追加
  • StartInputCommandPhase()でメッセージウィンドウを非表示にする処理を追加
  • メッセージの表示が完了した時のコールバックを追加

です。

イメージとしては、戦闘終了時のメッセージとして経験値やゴールドを表示する際に、ページ送り用カーソルを表示したいと思います。再度戦闘に入った時にカーソルが表示されたままになる可能性があるので、StartBattle()のメソッドで明示的にカーソルを消しておきたいと思います。

 

StartInputCommandPhase()のメソッドでは、メッセージウィンドウを非表示にしてコマンドウィンドウが表示されるようにします。

 

選択ウィンドウの実装時に追加したOnItemCanceled()の後ろに、メッセージ表示の完了が通知されるOnFinishedShowMessage()のメソッドを追加します。このメソッド内では、戦闘中のフェーズに応じて処理を分けていきます。敵が出現するフェーズであれば、メッセージ表示が完了した後にコマンド入力に移りたいので、StartInputCommandPhase()を呼んでいます。

 

スクリプトのアタッチ

スクリプトを保存したら、ゲームオブジェクトの作成してスクリプトをアタッチしましょう。

 

MessageUIControllerのアタッチ

まずはメッセージウィンドウのUIを制御するスクリプトからです。Hierarchyウィンドウから「MessageWindowParent」のゲームオブジェクトを選択します。

ゲームオブジェクトの選択
ゲームオブジェクトの選択

 

Inspectorウィンドウで今回作成した「MessageUIController」をアタッチします。フィールドにはそれぞれ対応する子オブジェクトをアサインします。

スクリプトのアタッチとアサイン
スクリプトのアタッチとアサイン

 

EnemyNameWindowControllerのアタッチ

続いてメッセージウィンドウを制御するクラスをアタッチしていきます。Hierarchyウィンドウで「BattleWindowManager」の下に空のゲームオブジェクトを作成します。名前は [MessageWindowController] にしました。

ゲームオブジェクトの作成
ゲームオブジェクトの作成

 

Inspectorウィンドウでは「MessageWindowController」のスクリプトをアタッチします。「Ui Controller」のフィールドには、先ほどスクリプトをアタッチした「MessageWindowParent」をアサインしましょう。

スクリプトのアタッチ
スクリプトのアタッチ

 

また、「BattleWindowManager」のスクリプトでもフィールドを追加したので、「MessageWindowController」をアサインしておきます。

参照のアサイン
参照のアサイン

 

動作確認

ここまでの設定を終えたら動作確認をしてみます。ゲームを実行して、「BattleTester」のスクリプトにて「Execute Battle」にチェックを入れて戦闘を開始します。画像のように敵キャラクターが出現したメッセージが表示された後、メッセージウィンドウが消えてコマンド入力に移ればOKです。

戦闘開始のメッセージ
戦闘開始のメッセージ

 

ここまで確認できたら今回は完了です。

 

今回のブランチ

 

まとめ

今回はメッセージウィンドウ内のUIと、ウィンドウ全体を制御するクラスを作成しました。メッセージウィンドウに関しては戦闘の内容をユーザに伝える重要な役割があるので、文字の表示時間に関しては適宜調整していただければと思います。

次回は戦闘の行動を処理するための機能の作成に入ります。全体の方針を考えつつ、できそうなところから着手していきましょう。

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!