【Unity】RPGを作るチュートリアルその70 メニュー画面の魔法機能の動作を実装

【Unity】RPGを作るチュートリアルその70 メニュー画面の魔法機能の動作を実装

シンプルなRPGをUnityで作るチュートリアルシリーズの70回目です。100回くらいで終わるかなーなんて見切り発車で始めたこのチュートリアルですが、終わる気がしません(涙目)

第69回ではメニュー画面のアイテム機能について動作を実装しました。

今回はメニュー画面の魔法機能について動作を実装していきます。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

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

 

チュートリアルの一覧

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

 

前回の内容

前回はメニュー画面のアイテム機能について動作を実装しました。

 

メニュー画面の実装方針

メニューの表示を確認
メニューの表示を確認

 

メニュー画面では、

  • アイテムの使用
  • 魔法の使用 ◀︎いまここ
  • 装備の選択
  • ステータスの確認
  • セーブ
  • ゲームの終了
  • メニューを閉じる

の項目を作成します。今回はこのうち、魔法使用の機能について実装していきます。

 

魔法機能の実装

魔法機能のUIについては、アイテム機能で作成したものがそのまま使えるので流用します。メニューのトップ画面でアイテムを選択した場合、魔法を選択した場合で処理を分岐させるようにします。ただ、アイテムの動作を作っているときに気づいたのが、アイテムや魔法選択時に現在のHPやMPを確認できた方が便利だということ。なので、HPやMPを表示するUIを配置します。

配置する位置は画面右側の説明文の下あたりがちょうど良いかもしれません。パーツ類は新しく作成する必要はなくて、戦闘画面のものを流用しましょう。多分これが一番楽だと思います。

魔法機能の動作は、項目表示のウィンドウのうち、魔法担当のクラスを追加するのと、メニュー内での魔法を処理するクラスを追加していきます。ウィンドウの動作自体はアイテムの時に実装しているので、主に分岐を増やす作業になります。

また、現在のHPやMPを表示することから、描画の処理を行うクラスも追加します。

 

UIの追加

アイテムや魔法を選択しているときに、現在のHPやMPを確認できるようにします。表示するためのUIに関しては、戦闘画面のものをそのまま複製して使いましょう。「BattleCanvas」の下にある「StatusParent」を複製し、マップの「Canvas」の下にある「ItemMenuParent」の子オブジェクトにします。

ゲームオブジェクトの複製
ゲームオブジェクトの複製

 

Inspectorウィンドウから、「Pos X」を [702] に、「Pos Y」を [-260] に設定します。ステータスのUIの左側がアイテム説明の左側と揃うようにしました。

Rect Transformの設定
Rect Transformの設定

 

メニュー画面のアイテム画面について非表示を解除すると、以下のように表示されます。ひとまずこれで進めていきましょう。

ステータス表示のUI
ステータス表示のUI

 

メニュー画面の魔法機能の実装

UIに関してはアイテム画面のものを使いまわせるので、機能作成に入ります。今回作成したいクラスは、

  • ウィンドウ内で魔法に関する処理を制御するクラス
  • 魔法の使用処理を行うクラス

です。これに加えて、既存のクラスについても変更を加えていきましょう。ステータスのウィンドウやUIを制御するクラスについては戦闘画面のものをそのまま流用してアタッチしていきます。また、ステータスの変動を確認しやすいように、デバッグ用のクラスとしてHPやMPを変更できるものを追加していきます。

 

ウィンドウ内で魔法に関する処理を制御するクラス

アイテムの時と同様に、ウィンドウ内で魔法に関する処理を制御するクラスを実装しましょう。このクラスでは、キャラクターが覚えている魔法をリストとして取得して、それを画面にセットするようにします。

魔法に関しては、今回のチュートリアルでは回復、移動の効果をもつものを使えるようにします。ただし、効果は複数持てるようにしているので、「回復または移動の効果を持つものを使えるようにする」のではなく、「戦闘、支援、効果なしの効果が含まれるものを使えないようにする」という方針で実装します。敵キャラクターにダメージを与えて、同時に味方を回復する、なんて効果はマップ上で使えると不自然ですもんね。

また、効果の対象に関しても、敵キャラクターが対象に含まれるものを選択できないようにします。とは言いつつチュートリアル内では自分を対象とした回復魔法ひとつしかないので、若干の拡張性を考えた実装になっています。

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

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

 

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

メニューのトップ画面で「魔法」を選択してウィンドウを表示した際に、こちらのクラスを使って魔法に関する情報を取得します。アイテムの場合はパーティ内の所持アイテムリストから有効なものを取得してリスト化していました。こちらのクラスでは、キャラクター個人のステータス情報から、習得している魔法のリストを取得します。

最大ページ数の取得や、インデックス等の確認についてはアイテムの時と同様です。対象の魔法が使えるかどうかについては、CanSelectMagic()のクラスで確認を行なっています。魔法の場合、魔法カテゴリと魔法の効果範囲、消費MPによって使えるかどうかを判断します。

魔法のカテゴリについては、HasUnusableCategory()のメソッドを使って、マップ上で使えるカテゴリの魔法かどうかを判断しています。魔法の効果が複数あることを考慮し、魔法効果のリスト内で対象外のカテゴリが含まれていればマップ上で使えないと判断します。今回のチュートリアルでは、ダメージを与える魔法、サポート系の魔法、効果なしの魔法が効果として含まれている場合は、マップ上で使えないようにします。といっても実装する魔法は回復魔法1つだけなので、ここは拡張性を考慮しての実装になります。

また、マップ上では敵を対象とする魔法も使えないようにしたいので、HasUnusableTarget()のメソッドを使って対象を確認しています。

 

魔法の使用処理を行うクラス

こちらもアイテムの時と同様に、魔法に関する使用処理を行うクラスを追加します。基本的な処理の流れは「BattleActionProcessorMagic」を踏襲します。また、メッセージ表示のタイミングと画面上のHP回復やMP消費のタイミングもうまく合わせつつ実装したいと思います。現在のステータスを画面に描画する点はアイテムと魔法で共通しているので、後ほどウィンドウ自体を管理するクラスに追加します。

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

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

 

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

基本の流れは戦闘画面の「BattleActionProcessorMagic」と一緒です。データ上でMPを減らしたあと、魔法の効果に応じて処理を行っていきます。魔法の効果はカテゴリごとに実装する想定でいますが、今回は回復魔法だけの実装になるので分岐は回復魔法の分だけになっています。メッセージ表示のタイミングでステータスを更新するように処理を入れています。UpdateStatus()のメソッドについては後ほど「MenuItemWindowController」に実装したいと思います。

 

デバッグ用にステータスを変更するクラス

アイテム画面、魔法画面でステータスのUIを表示するようにしました。アイテムや魔法を使う際に、現在のHPやMPを確認できるようにしておくとユーザも判断しやすくなるため、その動作を簡単に確認できるように、HPやMPを変更するためのデバッグ用のクラスを追加します。

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

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

 

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

「BattleTester」のクラスと同様に、Inspectorウィンドウでチェックボックスにチェックを入れると動作するようにします。既存の「CharacterStatusManager」のクラスにあるChangeCharacterStatus()のステータス変更のメソッドをそのまま使うので、フィールドとして変化量を指定するようにします。例えばHPを20減らしたいなら、Inspectorウィンドウで「-20」を入れてチェックボックスにチェックを入れます。

キャラクターのデータをロードする期間を待ちたいので、ゲーム開始後5フレーム目以降に動作するようにしています。変更後はコンソールにメッセージを出力するようにしています。

画面上のUIの更新処理は入れていないので、メニューを開き直すことで反映される想定です。

 

既存のクラスの変更

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

  • MenuManager
  • MenuItemWindowController
  • MenuProcessorItem
  • MapMessageWindowController
  • CharacterStatusSetter
  • CharacterDataManager

 

MenuManagerの変更

「MenuManager」ではメニュー選択後の分岐処理を変更していきます。メニュー選択時にメニューコマンドがフィールドに保存されるので、アイテムと魔法の区別はそこで行います。そうすると、アイテムと魔法では同じように項目選択画面を開けば内部で分岐するため、switch文の分岐ではアイテムと魔法で同じメソッドを呼ぶようにしました。

 

MenuItemWindowControllerの変更

こちらは各メソッド内でメニューコマンドによって分岐していた部分に、魔法メニューの分岐を追加していきます。個別のメソッドをコピペすると抜け漏れが怖いので、ちょっと長いですが全文を表示します。

SelectUpperItem()とSelectLowerItem()のメソッドでは、分岐なしでアイテムの所持数を直で参照している部分があったので、そこも変更を加えています。

ここまで多くのメソッドで分岐をつけるとなると大変なので、インタフェースで情報を返すメソッドを作っておいて、メニューに応じてどのインタフェースを使うかの分岐を1箇所で行うようにしておけば影響範囲が少なかったかもしれません(1敗)

フィールドでは魔法に関する処理を行う2つのクラスと、ステータスウィンドウを制御するクラスへの参照を保持するものを追加しています。このクラスの末尾にUpdateStatus()のメソッドを追加していて、これを使ってステータスUIの内容を更新するようにしています。

 

MenuProcessorItemの変更

HPの回復量を表示するメッセージのタイミング(2回目のwhileの前)にステータス更新の処理を入れています。

 

MapMessageWindowControllerの変更

魔法を唱えた時のメッセージ生成メソッドを追加します。追加といっても戦闘時のメッセージウィンドウで表示するものと同じになるので、コピペしてきました。既存のSetUpController()の後ろに追加しています。

 

CharacterStatusSetterの変更

ゲーム的には初期レベルは1の予定ですが、テストとしてレベルを変更できるように、「CharacterStatusSetter」で初期レベルを設定できるようにします。まずはフィールドとして初期レベルを設定できるものを追加します。既存の「_partyCharacters」の下に入れました。

 

続いて、キャラクターのステータスをセットアップするメソッドで、「var level」の変数に代入する際にフィールドの値を使うようにします。ここはもともと固定値で1を入れていました。

 

CharacterDataManagerの変更

アイテム側で存在しないIDの対策をしたので、魔法でも同様の対策を入れます。覚えられる魔法を取得する際に、存在しないIDの魔法が指定された場合にnullをリストに追加してしまっていたので、それを弾くようにしました。

 

スクリプトのアタッチ

スクリプトファイルを保存したら、ゲームオブジェクトにアタッチします。

 

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

必要なゲームオブジェクトについては先に作ってしまいましょう。

Hierarchyウィンドウから「MenuItemWindowController」の子オブジェクトを3つ作成し、名前をそれぞれ [MenuItemWindowMagicController] 、[MenuProcessorMagic] 、[StatusWindowController] にします。

また、「Managers」の下にも子オブジェクトを作成し、名前を [StatusChanger] にします。既存の「CharacterStatusSetter」の後ろに入れました。

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

 

MenuItemWindowMagicControllerのアタッチ

作成した「MenuItemWindowMagicController」のゲームオブジェクトに「MenuItemWindowMagicController」のスクリプトファイルをアタッチします。

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

 

MenuProcessorMagicのアタッチ

同様に作成した「MenuProcessorMagic」のゲームオブジェクトに「MenuProcessorMagic」のスクリプトファイルをアタッチします。

スクリプトのアタッチ(2つ目)
スクリプトのアタッチ(2つ目)

 

StatusUIControllerのアタッチ

ステータスのUIを制御するクラスを先にアタッチしておきます。ヒエラルキーウィンドウから今回追加した「StatusParent」を選択します。

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

 

Inspectorウィンドウでは「StatusUIController」のスクリプトファイルをアタッチし、対応するUIをアサインします。

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

 

StatusWindowControllerのアタッチ

作成した「StatusWindowController」のゲームオブジェクトに「StatusWindowController」のスクリプトファイルをアタッチします。「Ui Controller」のフィールドには先ほどスクリプトファイルをアタッチした「StatusParent」をアサインします。

スクリプトのアタッチと参照のアサイン
スクリプトのアタッチと参照のアサイン(2つ目)

 

StatusChangerのアタッチ

デバッグ用に「StatusChanger」のゲームオブジェクトに「StatusChanger」のスクリプトファイルをアタッチします。

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

 

こちらはゲーム実行時に必要に応じて値を入れて使っていきます。

 

動作確認

スクリプトのアタッチが完了したら動作を確認していきます。

今回確認したいのは、

  • メニュー画面で「魔法」を選択した時に魔法の一覧が表示されること
  • 魔法画面で回復魔法が使えること
  • 魔法使用時にHPとMPが画面に反映されること

です。もし余力があれば、魔法データをいくつか追加してみて、カテゴリごとに選択できるかどうかを確認しておくとグッドです。

メニュー画面に関するゲームオブジェクトを非表示にした後、「CharacterStatusSetter」の「PlayerLevel」を2以上にしてゲームを実行します。メニューを開いて、魔法メニューを選択し、魔法の一覧が表示されることを確認します。また、右側にHPやMPが表示されることも確認しておきます。魔法を使ってみて、メッセージが表示されることも確認しておきましょう。事前にHPを減らしておくと回復した様子がわかります。魔法使用後はMPが減っていることも確認します。

魔法を使ってみる
魔法を使ってみる

 

たくさん魔法を覚えた場合は以下のように表示されます。ヒールは回復魔法、「Movement魔法」は移動魔法で使用できるようになっています。ただ、移動魔法の分岐は作っていないので「未定義の魔法効果です。」とコンソールに表示されます。

たくさん魔法を覚えた例
たくさん魔法を覚えた例

 

ここまで確認できれば今回は完了です。今回も長くなってしまいましたね(白目)

 

今回のブランチ

 

まとめ

今回はメニュー画面の魔法の機能について動作を実装しました。UIに関してはアイテム画面とほとんど共通して使えたので多少は楽に進められたような気がします。

次回はメニュー画面の装備の機能について、まずはUIから作成していきます。

     

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

CTA-IMAGE

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


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


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