【Unity】RPGを作るチュートリアルその109 タイトルメニューの機能を実装

【Unity】RPGを作るチュートリアルその109 タイトルメニューの機能を実装

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

第108回ではタイトル画面のUIを実装しました。

今回はタイトル画面の動作のうち、タイトルメニューの部分を実装していきます。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

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

 

チュートリアルの一覧

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

 

前回の内容

前回はタイトル画面のUIを実装しました。

 

タイトル画面の構成

タイトル画面では、シーン全体を管理するクラスを用意します。このクラスではゲーム全体の初期化機能を担当します。

タイトルのメニューに関しては、メニューの処理分岐を担当するクラス、メニュー表示時のキー操作を制御するクラス、メニューのUIを制御するクラスに分けておきます。

選べる3つのメニューに対して、それぞれ制御用のクラスを作成していきます。今回はそれぞれのクラスは作らず、次回以降実装していきましょう。

また、初期化の状況やロード対象のスロットIDなど、シーンを跨いでゲームの開始に必要な情報があるため、これらを保持するためのstaticなクラスを作成します。

どのタイトルメニューを選んだかを保持するため、他の項目選択のウィンドウのようにEnumも作成しておきたいと思います。タイトル画面も作るクラスが多いですがひとつずつ進めていきましょう。

 

タイトル画面の動作の実装

今回実装するのは、

  • タイトルメニューの項目のEnum
  • 初期化状態を保持するクラス
  • シーン全体を管理するクラス
  • メニューの処理分岐を担当するクラス
  • メニューのUIを制御するクラス
  • メニュー表示時のキー操作を制御するクラス

です。ちょっと量が多いですが頑張りましょう(白目)

 

タイトルメニューの項目のEnum

タイトルメニューの項目に対応するEnumを作成しましょう。Projectウィンドウから「Assets/Scripts/Enums」のフォルダを開き、空のスクリプトファイルを作成します。名前は [TitleCommand] にしました。

スクリプトの作成
スクリプトの作成

 

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

タイトルメニューの項目に合わせて、それぞれ実装しています。

 

初期化状態を保持するクラス

タイトル画面で「はじめから」を選んだのか、それとも「つづきから」を選んだのかどうかによって、ゲーム用のシーンで処理を分けていきます。「はじめから」の場合は初期状態でゲームを開始して、「つづきから」の場合は選択されたセーブ枠のIDをもとにデータをロードします。

これらの情報を保持するためのクラスを作成しておきましょう。

Projectウィンドウから「Assets/Scripts」のフォルダを開き、タイトル画面関連のスクリプトファイルを配置するため、新しいフォルダを作成します。名前は [Title] にしました。

フォルダの作成
フォルダの作成

 

作成した「Title」フォルダに移動し、空のスクリプトファイルを作成します。名前は [GameStartInfoHolder] にしました。

ゲーム開始の情報を保持するクラス
ゲーム開始の情報を保持するクラス

 

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

staticなクラスとして作成し、シーンを跨いでもデータが保持されるようにします。「isNewGame」のフラグがtrueの場合は初期状態からゲームを開始するようにします。「つづきから」を選んだ時に「isNewGame」のフラグをfalseにしつつ、選択されたセーブ枠のIDを「loadedSlotId」にセットします。

「isThroughInitScene」はタイトル画面からゲームを開始した場合にtrueになるフラグです。「Game」シーンから直接ゲームを開始した場合はこのフラグがfalseになるので、リソースのロードなどの初期化処理を行うことで、「Game」シーン単体でも動作確認ができるようにしています。

 

シーン全体を管理するクラス

シーン全体の動作を管理するクラスを作成します。このクラスでは、リソースのロードなど、タイトル画面でやっておく準備作業などを行います。タイトルメニューの動作などは別のクラスを作ってそこで制御していきます。

Projectウィンドウから「Assets/Scripts/Title」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [TitleManager] にしました。

タイトル画面全体を管理するクラス
タイトル画面全体を管理するクラス

 

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

画面のフェードインを行うため、「IFadeCallback」のインタフェースを実装しています。

「_titleMenuManager」はこの後作成するクラスで、フェードインの処理が完了後にメニューの選択開始用のメソッドが呼び出されます。

「_resourceLoadWaitTime」のフィールドはリソースのロードを待つ時間です。今回のチュートリアルではAddressablesのリソースをロードするのに1フレーム程度でいけるかと思いますが、ざっくりと0.5秒待つ形にしています。リソースの多いゲームではロードに時間がかかることがあるので、各リソースがロードされたかどうかを確認してから開始処理に進むと良いかと思います。

Start()では「ResourceLoader」のロード用の処理を呼び出しています。現時点では「ResourceLoader」はMonoBehaviourを継承するクラスになっているので、今回の後半でstaticなクラスに変更したいと思います。

StartProcess()のコルーチンでは「_resourceLoadWaitTime」のフィールドで指定した時間だけ処理を待った後、画面をフェードインさせます。

OnFinishedFade()はフェードインが完了したタイミングで呼ばれ、「GameStartInfoHolder」のクラスにある「isThroughInitScene」のフィールドにフラグをセットした後、「_titleMenuManager」に制御を渡しています。

 

メニューの処理分岐を担当するクラス

次にメニューの処理分岐を行うクラスを作成します。キー入力に対する画面上の反映は別クラスで行なうとして、このクラスでは選択されたメニューの情報を保持しつつ、処理を分岐させるようにします。

Projectウィンドウから「Assets/Scripts/Title」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [TitleMenuManager] にしました。

メニューの分岐処理を行うクラス
メニューの分岐処理を行うクラス

 

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

フィールドで参照しているクラスはこの後作成していきます。「_titleMenuWindowController」はキー操作を制御するクラスへの参照、「_titleStartController」はゲーム開始の処理を行うクラスへの参照、「_titleQuitGameController」はゲーム終了の処理を行うクラスへの参照になっています。

InitializeMenu()のメソッドではメニューのコマンド選択を初期状態にしています。

StartSelect()のメソッドではキー操作を制御するクラスのセットアップを行なって、メニューを選択できるようにします。メニューが選択された場合には、OnSelectedMenu()のメソッドが呼び出され、選択されたメニューに応じてHandleMenu()のメソッドで処理を分岐させていきます。

HandleMenu()のメソッドでは、対応するメニューの処理用クラスの処理を呼び出します。今回は「はじめから」と「ゲームの終了」のメニューに対応する処理を作成し、「つづきから」に対応する処理は次回以降に実装予定です。

OnLoadCanceled()のメソッドやOnSelectedSlotId()のメソッドはセーブファイルの選択画面からのコールバックとして用意しています。

 

メニューのUIを制御するクラス

メニューのUIを制御するクラスを作成します。このクラスではどのカーソルを表示するかなどの制御を行います。

Projectウィンドウから「Assets/Scripts/Title」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [TitleMenuUIController] にしました。

UIを制御するクラス
UIを制御するクラス

 

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

カーソル画像への参照をフィールドとして保持し、現在選択されているメニューに応じて画像を表示します。この部分は他のUI制御のクラスと同じ形になっています。

 

メニュー表示時のキー操作を制御するクラス

続いてメニュー表示時のキー操作を制御するクラスを作成します。

Projectウィンドウから「Assets/Scripts/Title」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [TitleMenuWindowController] にしました。

キー入力を制御するクラス
キー入力を制御するクラス

 

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

「_uiController」のフィールドでは先ほど作成したUI制御のクラスへの参照を保持します。選択されたコマンドを通知するため、「_titleMenuManager」のフィールドで「TitleMenuManager」への参照も保持しています。他のウィンドウ制御系クラスと同様に、SetUpController()のメソッドを使って参照をアサインするようにしています。

基本的な流れはこちらも他の制御系クラスと同様で、「_canSelect」で選択できる状態になっている場合にキー入力の上下に応じてカーソルを移動させ、決定ボタンで選択されたメニューを「TitleMenuManager」に通知します。

 

既存のクラスの変更

今回作成したクラスに合わせて、既存のクラスも変更していきます。変更したい対象のクラスは「ResourceLoader」です。

 

ResourceLoaderの変更

「ResourceLoader」はシーン内に配置するMonoBehaviourのクラスとして作成してありましたが、このクラス自体では特に状態を持たず、各データ管理クラスのロード処理を実行するだけなので、staticなクラスに変更します。

クラスの宣言にstaticを追加し、「MonoBehaviour」を継承していた部分を削除しました。また、LoadDefinitionData()のメソッドでも同様にstaticにしています。

また、元々「Game」シーンでは「ResourceLoader」をゲームオブジェクトにアタッチしていたので、このゲームオブジェクトを削除します。「Game」シーンを開き、「Managers」の子オブジェクトの「ResourceLoader」を削除してシーンを保存しましょう。

ResourceLoaderを削除する
ResourceLoaderを削除する

 

スクリプトのアタッチ

作成したスクリプトをアタッチしていきます。先ほど別のシーンを開いたので、再度「Title」シーンを開いておきましょう。

Hierarchyウィンドウから「TitleScreen」の子オブジェクトの「MenuBackground」のゲームオブジェクトを選択し、既存の「TopMenuUIController」を外した後、「TitleMenuUIController」をアタッチします。名前が似ていて紛らわしいですが、「Title」と付いていてフィールドが3つの方をアタッチしましょう。カーソルへの参照もアサインしておきます。

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

 

ちなみに前回の作業では、カーソルのゲームオブジェクトがまだアイテムや魔法の名前だったかと思います。こちらの名前もタイトル画面に合わせて変更しておきましょう(すみません)

カーソルの名前の変更
カーソルの名前の変更

 

Hierarchyウィンドウから「Managers」の下に、以下の3つのゲームオブジェクトを作成し、同名のスクリプトファイルをアタッチします。

ゲームオブジェクト名 アタッチするスクリプトファイル
TitleManager TitleManager
TitleMenuManager TitleMenuManager
TitleMenuWindowController TitleMenuWindowController

 

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

 

アタッチしたスクリプトでは、他のクラスへの参照をアサインしておきましょう。

 

動作確認

スクリプトをアタッチしたら動作を確認してみましょう。今回は、

  • ゲームを開始して画面がフェードインすること
  • タイトル画面のメニューで上下キーでカーソルが移動すること
  • 決定ボタンを押すとコンソールに選択したメニューが出力されること

を確認します。決定ボタンを押すと処理が止まるので、都度ゲームを停止してから再度開始します。

あの呪いの音が聞こえてきそうな画面。おきのどくですが(ry
あの呪いの音が聞こえてきそうな画面。おきのどくですが(ry

 

今回のブランチ

 

まとめ

今回はタイトル画面の動作のうち、タイトルメニューの部分を実装しました。タイトル画面では初期化処理など、フェーズに応じた準備作業などもあるため、処理を行うクラスを分けておくと対応しやすくなるかもしれません。

次回はタイトル画面の動作のうち、「はじめから」と「ゲームの終了」の動作を実装したいと思います。

     

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

CTA-IMAGE

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


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


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