【Unity】RPGを作るチュートリアルその112 ゲームの続きから開始する機能を実装

【Unity】RPGを作るチュートリアルその112 ゲームの続きから開始する機能を実装

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

第111回ではシーンに依存しない形でマップ名を取得する機能を実装しました。

今回はタイトル画面の動作のうち、「つづきから」の動作を実装していきます。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

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

 

チュートリアルの一覧

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

 

前回の内容

前回はシーンに依存しない形でマップ名を取得する機能を実装しました。

 

ゲームの再開の動作

タイトル画面のメニュー項目としては、

  • はじめから
  • つづきから
  • ゲームの終了

の3つで、残っている「つづきから」の動作を実装していきます。

「つづきから」を選択した時の動作を制御するクラスを作成し、その中でロード画面の表示/非表示なども制御していきたいと思います。また、各セーブファイルの情報も画面上にセットする動作についても実装します。前回の作業でシーンに依存しない形でマップ名を取得できるようになったので、これを使ってロード画面でもマップ名を表示したいと思います。

ロード画面ではどのセーブデータを選択するかによって「GameStartInfoHolder」のクラスにある「loadedSlotId」のフィールドにセットする値が変わります。この値は前回追加した「GameSceneManager」の中で確認していきます。

また、読み込んだセーブデータは「SaveDataManager」で保持するようにしていましたが、ファイルの読み書きと、ゲーム内データとのやり取りが一緒のクラスになっているため、より役割を明確にするために分離したいと思います。また、セーブデータへのアクセスは「Title」シーンと「Game」シーンの両方で行うため、それに対応する形で実装していきます。

まずはセーブファイル関連の機能を先に変更して、その後に「つづきから」の処理を実装していきます。

 

セーブ機能に関する変更

上で触れた通り、「SaveDataManager」の機能を分離して、ファイルの読み書きをメインにするクラス、ゲーム内データとのやり取りを行うクラスに分けたいと思います。後者のゲーム内データとのやり取りを行うクラスは、シーン内の他のクラスも参照することからMonoBehaviourのクラスのままで使いたいため、このまま「SaveDataManager」として残しておきます。

前者のファイルの読み書きをメインにするクラスでは、シーンに依存しない形で参照できるようにstaticなクラスとして別のクラスを作成します。

 

ファイルの読み書きをメインにするクラス

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

セーブデータを保持するクラス
セーブデータを保持するクラス

 

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

staticなクラスとして作成し、「SaveDataManager」で保持していた「_saveFile」のフィールドをそのままこちらに移動しました。他のクラスから参照するのに便利なため、プロパティとして「SaveFile」を新たに追加しています。

InitializeSaveFile()は名前を変更せず移動し、Load()はLoadFile()だったものを移動して名前を変更しました。

Save()はSaveDataToFile()のファイルへの書き込み部分を移動してきました。

 

ゲーム内データとのやり取りを行うクラス

既存の「SaveDataManager」はゲーム内データとのやり取りを行うクラスとして使用します。セーブファイルに関する処理を「SaveDataHolder」に移動したのに合わせて変更しました。フィールドを直接参照していた部分が多かったため、スクリプトの全文を表示します。

「SaveDataHolder」に移動した処理を削除しました。それに合わせて、「_saveFile」のフィールドを参照していた部分について「SaveFile」のプロパティを参照するようにしました。

変更した箇所は多いですが、変更の種類はそんなに多くありません。

 

ResourceLoaderの変更

ゲームの実行を開始したタイミングでセーブファイルをロードするようにしたいので、「ResourceLoader」に処理を追加します。

LoadDefinitionData()のメソッドにて、「SaveDataHolder」のクラスにあるLoad()を呼ぶようにしました。ファイルの中身については最初に読み込んでしまえばあとはロードする必要はないので、他のリソース類を読み込むタイミングで一緒にロードしておきます。

 

SaveTesterの変更

「SaveTester」ではStart()のタイミングでセーブファイルを読み込む処理を行っていましたが、上で変更した「ResourceLoader」によってその動きが実現できているので、このクラスからのロード処理は削除します。

先述の通り、Start()内のロード処理を削除しています。

 

つづきからの処理の実装

準備ができたので「つづきから」を選択した時の処理を実装していきましょう。「はじめから」や「ゲームの終了」の時と同様に、「つづきから」を選択した時の動作を制御するクラスを作成します。

このクラスでは、ロード画面でセーブ枠の情報をセットする処理、ロード画面の操作を実装しましょう。

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

「つづきから」の動作を制御するクラス
「つづきから」の動作を制御するクラス

 

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

フィールドとしては、選択結果を通知するための「TitleMenuManager」への参照、UIを操作するための「MenuSaveUIController」への参照、セーブ枠の情報を取得するための「SaveDataManager」への参照をそれぞれ保持するようにします。「_selectedSlot」では選択されたセーブ枠IDを保持し、「_canSelect」ではロード画面で操作ができるかどうかの状態を保持します。

画面上部の説明ウィンドウにテキストを表示するため、「LoadDescription」のフィールドで文字列を定義しています。といってもセーブ画面の「セーブ」の文字を「ロード」に変えただけです。使い回し万歳。

SetUpSlotInfo()ではセーブデータの情報から画面上に値をセットしていきます。マップ名取得のための処理をstaticなクラスに移行したことで、「Title」画面内でもマップ名を取得することができます。

操作部分に関してはメニューのセーブ画面とほとんど同じで、決定ボタンを押した時の処理のOnPressedConfirmButton()で「TitleMenuManager」のOnSelectedSlotId()を呼んで選択されたIDを渡すようにしています。

 

既存のクラスの変更

今回作成したクラスに合わせて、既存のクラスも変更していきましょう。変更したいクラスは以下の通りです。

  • TitleMenuManager
  • FlagManager
  • SaveInfoFlagController
  • FlagTester

 

TitleMenuManagerの変更

「TitleMenuManager」では「TitleContinueController」への参照をフィールドとして保持し、「つづきから」を選択した時にはロード画面を表示するようにします。

タイトルメニューの並びに合わせて、「_titleStartController」と「_titleQuitGameController」の間に、今回作成した「TitleContinueController」への参照用フィールドを追加しました。

 

HandleMenu()の分岐で、「つづきから」を選択した時の処理を記載しました。このクラスへの参照を渡しつつ、ロード画面を表示します。

 

FlagManagerの変更

「FlagManager」ではフラグリストの初期化をUpdate()の中で行なっていましたが、ゲームを開始するタイミング、あるいはセーブからデータをロードするタイミングで初期化処理を呼び出すようにしたので、このクラス内で初期化する部分を削除したいと思います。

Start()とLoadFlagNames()の間にあったUpdate()を削除しました。

 

SaveInfoFlagControllerの変更

「SaveInfoFlagController」ではセーブデータからフラグに関する情報をセットする役割を持っていますが、フラグ管理のクラスをシングルトンにしたため、そのインスタンスを参照するように変更します。

「FlagManager」への参照用フィールドを削除し、クラス内では「FlagManager.Instance」を参照するように変更しました。

 

FlagTesterの変更

「FlagTester」でも同様に、「FlagManager」のstaticなインスタンスを参照するように変更します。

フィールドを削除し、「FlagManager.Instance」を使うように変更しています。

 

スクリプトのアタッチ

作成したスクリプトをアタッチしていきましょう。

「Title」シーンにて、Hierarchyウィンドウから「Managers」の子オブジェクトとして空のゲームオブジェクトを作成します。名前は [TitleContinueController] にしました。

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

 

作成した「TitleContinueController」には同名のスクリプトをアタッチします。参照もアサインしましょう。

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

 

「TitleMenuManager」では、先ほど作成した「TitleContinueController」への参照をアサインします。

「つづきから」の動作を制御するクラスへの参照
「つづきから」の動作を制御するクラスへの参照

 

動作確認

ゲームを再開する機能について確認していきます。「Title」シーンからゲームを実行し、「つづきから」を選択します。ロード画面が表示されることを確認し、任意のセーブ枠を選択してゲームを開始します。この時、セーブしたマップや位置、レベルなどが合っていることを確認しましょう。

セーブデータをロードする
セーブデータをロードする

 

今回のブランチ

 

まとめ

今回はタイトル画面の動作のうち、「つづきから」の動作を実装しました。どのクラスでセーブデータを読み書きするか、読み込んだセーブデータはどのクラスで保持するか、といったセーブデータの管理はシーンと切り離しておくと扱いやすくなるかもしれません。

次回はオーディオの再生や停止を管理するクラスを作成していきます。

 

     

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

CTA-IMAGE

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


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


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