【Unity】RPGを作るチュートリアルその95 宿屋に関するイベントを実装

【Unity】RPGを作るチュートリアルその95 宿屋に関するイベントを実装

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

第94回ではフェードイン、フェードアウトの機能を実装しました。

今回はHP/MPが全回復するイベントや待ち時間を発生させるイベント、選択肢を呼ぶイベントを実装していきます。これらを組み合わせて宿屋の処理を実装します。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

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

 

チュートリアルの一覧

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

 

前回の内容

前回はフェードイン、フェードアウトの機能を実装しました。

 

宿屋の処理

RPGではHP/MPを全回復させる手段が大切です。多くの場合宿屋として実装されているので、これにならって宿屋の処理と呼ぶことにします。今回のチュートリアルでは村にいる母親が宿屋の役割を持っています。ゴールドは不要で、泊まるかどうかの選択肢を表示して、泊まる場合は全回復させるようにします。

必要そうなイベントプロセスとしては、

  • 全回復の処理
  • 待ち時間を発生させる処理
  • 選択肢を表示する処理

です。既に作成済みのメッセージ表示の処理、フェードイン、フェードアウトの処理も組み合わせて宿屋に関する一連の流れが実装できそうです。

 

全回復の処理の作成

「CharacterStatusManager」にパーティメンバー全員を全回復させる処理を実装し、イベント側からそれを呼び出すようにしたいと思います。既存のChangeCharacterStatus()の中では、キャラクターのレベルに応じた最大値の確認も行うようにしているので、シンプルにシステム上の最大HP、最大MPを渡すことで、上限に補正するようにします。

やりたい作業としては、

  • システム的な上限値を保持するクラスの作成
  • 「CharacterStatusManager」へのメソッド追加
  • 全回復イベントの作成

となるので、順番に作成していきます。

 

システム的な上限値を保持するクラスの作成

ゲーム内では様々な値を持ちますが、それぞれの上限値を決めておくのも大切です。例えばパラメータの上限値などを決めておくことで、UIの配置もしやすくなります。アイテムや経験値の上限値についても決めておくと桁あふれなどを防げます。

こうした上限値の定義は必要なクラスの冒頭に書いておいてもいいですし、定義用のクラスを用意しても良いかと思います。私は定義用のクラスを作ることが多いので、今回は専用にクラスを作っていきたいと思います。

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

値に関する定義値用のクラス
値に関する定義値用のクラス

 

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

まずは今回使うHPとMPの上限値を実装しました。この後のチュートリアルでも必要な値を追加していきたいと思います。

 

「CharacterStatusManager」へのメソッド追加

パーティメンバー全員を全回復させるメソッドを「CharacterStatusManager」に追加します。

既存のIsCharacterDefeated()のメソッドの前に、全回復させるメソッドのRefreshPartyCharacter()を追加しました。やっていることは単純で、partyCharacterのリスト内のキャラクターIDについて、foreachで回してChangeCharacterStatus()で回復処理を行います。

指定する値はValueSettingsで定義した値を渡します。ChangeCharacterStatus()の中では元々キャラクターの最大HPや最大MPに合わせて補正するようにしていて、今回のレベルアップの範囲ではValueSettingsまでは届かないのでパラメータの最大値への補正にとどめています。もしアクセサリでHP10%アップ、といった効果がある場合はパラメータの最大値より大きくなる可能性があるため、上限値による補正処理も入れておくと良いかと思います。

 

全回復イベントの作成

イベントとして全回復イベントを作成していきます。

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

全回復のイベント
全回復のイベント

 

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

Execute()の中で、先ほど「CharacterStatusManager」で作成したRefreshPartyCharacter()を呼び出して全回復の処理を行います。処理が終われば次のプロセスを呼び出します。

やることはこれだけなのでシンプルですね。

 

待ち時間を発生させる処理の作成

待ち時間を発生させるイベントはシンプルで、イベントの処理内でコルーチンを使って指定時間待った後、次のプロセスを呼び出すようにします。

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

待ち時間のイベント
待ち時間のイベント

 

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

フィールドとして「_waitTime」を作成していて、Inspectorウィンドウから待ち時間を設定できるようにしています。

このクラスも処理自体はシンプルで、Execute()からコルーチンを起動し、指定の秒数だけ待ってから次のプロセスを呼び出します。

待ち時間の処理は、

  • 会話の区切りを作る
  • キャラクターが思案している様子を表現する
  • 何らかの時間経過が発生していることを伝える

などなど、表現の上でも大切だったりします。

 

選択肢を表示する処理の作成

選択肢のUIを表示する機能についてはメニュー画面でゲームを終了させる機能を作成したときに実装しました。汎用的に呼び出せるようにしているので、こちらを使うようにしましょう。

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

選択肢を表示するイベント
選択肢を表示するイベント

 

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

選択肢の結果によって次に実行するイベントプロセスを変えられるように、「_nextProcessYes」と「_nextProcessNo」を作成しました。ベースクラスの「_nextProcess」と合わせて、はい、いいえ、キャンセルの3通りの分岐ができるようになっています。

「_optionIndexNo」のフィールドでは、選択肢ウィンドウを表示した際のデフォルトのカーソル位置を設定します。「_hideMessageWindow」は選択肢を選んだ後にメッセージウィンドウを閉じるかどうかのフラグで、基本的にはtrueで運用しつつ、必要に応じてfalseにして表示したままにします。

Execute()ではまず参照のセットアップを行います。SetUpReference()のメソッドではメッセージウィンドウの管理クラス、選択肢ウィンドウの管理クラスへの参照を取得しています。選択肢ウィンドウを取得する際にはFindAnyObjectByType()ではなくFindObjectsByType()を使って複数のコンポーネントを取得しています。これは後のチュートリアルでお店を作る際に、お店用に選択肢ウィンドウを作成する予定ですが、既存の選択肢ウィンドウを継承して作成します。FindAnyObjectByType()を使うとお店の方の選択肢ウィンドウを取得することがあったので、「OptionWindowController」と派生クラスを取得した後、GetType()で型を確認するようにしています。

選択肢ウィンドウを表示して、選択された後は選択肢に応じて次に実行するプロセスを切り替えます。CallNextProcess()では引数で渡すプロセスがあればそれを呼び出す形にしているので、分岐を実現することができます。

 

スクリプトのアタッチ

作成したスクリプトをイベントとしてアタッチしていきます。

まずはHierarchyウィンドウから「NPC_Mother」を「Map_0001_Village」の中にある「NPC」の子オブジェクトにします。「NPC_Mother」が非表示になっていた場合は表示に切り替えます。

母親のゲームオブジェクト
母親のゲームオブジェクト

 

Projectウィンドウの「Assets/Prefabs」のフォルダから、「EventFileData」をドラッグ&ドロップして「NPC_Mother」の子オブジェクトにします。この中にイベント用のプロセスを作成していきましょう。

「EventGraphicController」の方は今のところグラフィックを変えないため変更なしでOKです。エンディングを作成するときに設定を入れていく予定です。

「EventPages」の下にある「EventPage」の中で、「Processes」の下にイベント用のプロセスを作成していきましょう。

宿屋のイベントの流れは以下のものを考えています。母親に話しかけると、

  • メッセージ表示(泊まってく?)
  • 選択肢の表示

の流れで、「はい」を選択した場合は、

  • メッセージ表示(ゆっくりおやすみ)
  • フェードアウト
  • 全回復
  • 待ち時間
  • フェードイン
  • メッセージ表示(頑張ってね)

の流れで進め、「いいえ」を選択した場合は、

  • メッセージ表示(無理しないでね)

と進めていきます。「はい」の場合の処理と「いいえ」の場合の処理が目で見て分かるように、区切り用のゲームオブジェクトも作成していきます。作成するゲームオブジェクトは以下の表の通りです。アタッチするスクリプトも以下のようにします。

ゲームオブジェクト名 アタッチするスクリプト
ShowMessage EventProcessMessage
ShowOption EventProcessShowOption
Yes———- なし
ShowMessageYes EventProcessMessage
FadeOut EventProcessFadeOut
Refresh EventProcessRefresh
Wait EventProcessWait
FadeIn EventProcessFadeIn
ShowMessageBye EventProcessMessage
No———- なし
ShowMessageNo EventProcessMessage

 

イベントプロセスの作成
イベントプロセスの作成

 

ShowMessageは複数ありますが、「Next Process」で参照をアサインする際にメッセージを区別できるように簡易的に名前を分けています。メッセージについては以下のように入力しました。話しているのが誰か分かるように名前も入れています。チュートリアル内ではこの表記で進めていきます。

ゲームオブジェクト名 メッセージ(表の1セルがリストの1要素)
ShowMessage <母親>
アレン、無理はしなくていいからね。
(同上) <母親>
ちょっと休んでいく?
ShowMessageYes <母親>
ゆっくりおやすみ。
ShowMessageBye <母親>
気をつけていってらっしゃい、アレン。
ShowMessageNo <母親>
分かったわ。
疲れた時にはいつでも戻ってきていいからね。

 

続いて「Next Process」を以下の表のように指定します。「ShowOption」は複数のフィールドがあるので表の下に画像で補足します。

ゲームオブジェクト名 フィールド名 アサインするプロセス
EventPage Start Process ShowMessage
ShowMessage Next Process ShowOption
ShowOption Next Process ShowMessageNo
Next Process Yes ShowMessageYes
Next Process No ShowMessageNo
ShowMessageYes Next Process FadeOut
FadeOut Next Process Refresh
Refresh Next Process Wait
Wait Next Process FadeIn
FadeIn Next Process ShowMessageBye
ShowMessageBye Next Process なし
ShowMessageNo Next Process なし
選択肢の設定
選択肢の設定

 

また、選択肢を表示する際は、質問文のメッセージを表示したままにしたいので、「ShowMessage」のゲームオブジェクトにて、Inspectorウィンドウから「Keep Window Open」にチェックを入れておきます。

メッセージを表示したままに
メッセージを表示したままに

 

さらに、「EventPage」ではイベントの起動方法として [Confirm Button] を選択します。

イベントの起動方法
イベントの起動方法

 

最後にゲームオブジェクトの位置を変更します。村のマップにて、左の家の机あたりに配置されるようにしたいと思います。リポジトリのマップを使っている場合は、「NPC_Mother」の「Transform」にて、「Position」の「X」を [-0.5] に、「Y」を [6.5] に設定します。

位置の設定
位置の設定

 

ここまでの設定が終わったら、「Map_0001_Village」の「Overrides」のプルダウンから [Apply All] をクリックしてPrefabに変更を適用します。

 

動作確認

宿屋の動作を確認してみましょう。確認前に、「Map_0001_Village」を非表示にしておきます。

母親の方向を向いて決定ボタンを押して、設定したイベントの流れになることを確認します。「はい」を選択したらフェードアウトして全回復の処理、「いいえ」を選択したらメッセージが表示されてイベントが終了することを確認します。

宿屋の処理
宿屋の処理

 

チュートリアルの中では導入しませんが、通常のRPGであれば宿屋でお金を払うことが多いので、所持金の確認処理も入れておくと良いかと思います。その場合、条件判定のイベントプロセスを作成し、選択肢イベントのようにその結果に応じて分岐させると実現できそうです。

 

今回のブランチ

 

まとめ

今回はHP/MPが全回復するイベントや待ち時間を発生させるイベント、選択肢を呼ぶイベントを実装しました。これらを組み合わせて宿屋の処理も実現できました。RPGだと回復できる場所は大切ですね。

次回は宝箱の処理を実装していきます。アイテム増減、所持金増減、フラグの設定、画像切り替えのイベントプロセスを作って実現していきましょう。

 

     

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

CTA-IMAGE

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


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


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