ユニティちゃんのRPGを作ってみよう29ー戦闘終了後の結果画面とその後の処理の作成ー | Unityを使った3Dゲームの作り方(かめくめ)

ユニティちゃんのRPGを作ってみよう29ー戦闘終了後の結果画面とその後の処理の作成ー

今回は戦闘終了後の結果画面を作成していきたいと思います。

前回は戦闘中のカメラワークを作成しました。

ユニティちゃんのRPGで戦闘中でターンが回ってきているキャラクターをフォーカスする等のカメラワークを作成していきます。

ユニティちゃんのRPGを作ってみようの他の記事は

から見ることが出来ます。

前回までで戦闘のシステムを作成し、敵の攻撃、味方の攻撃を行えるようにしました。

なので戦闘を繰り返していると敵か味方のパーティーが全滅し、戦闘が終了します。

今回は戦闘の結果、敵の全滅、味方の全滅、戦闘から逃げるのに成功した時に戦闘結果を表示する機能を作成します。

また敵を倒した時と戦闘から逃げ出した時はワールドマップシーンの敵と遭遇した位置に戻し、味方が全滅した時は最初の村に戻すようにします。

スポンサーリンク

戦闘終了画面UIの作成

まずは戦闘終了時に表示するUIを作成していきます。

BattleシーンのBattleUIを選択した状態で右クリックからUI→Panelを選択し、名前をResultPanelとします。

ResultPanelのImageのColorは黒にし、Aを255にして透けないようにします。

ResultPanelのサイズはゲーム画面全体より少し小さくします。

ユニティちゃんRPGのResultPanelのサイズ

ResultPanelを選択した状態で右クリックからUI→Textを選択し、名前をTitleTextとします。

TitleTextは結果画面のタイトルを表示する場所です。

Textに戦闘終了という文字列を入力し、Font Sizeを50にして大きめにします。

ParagraphのAlignmentを真ん中にし、Colorを白色にします。

ユニティちゃんRPGの戦闘シーンのResultPanel子要素のTitleTextのインスペクタ

TitleTextはResultPanelの上側に位置するようにします。

ユニティちゃんRPGのResultPanel子要素のTitleTextの位置とサイズ

ResultPanelを選択した状態で右クリックからUI→Panelを選択し、名前をResultTextMaskとします。

ResultTextMaskは取得した経験値などを表示する領域のマスクの領域に使い、子要素のUI要素がResultTextMaskの領域外に出た時は表示しないようにします。

ResultTextMaskのインスペクタのAdd ComponentからUI→Maskを選択し取り付けます。

インスペクタでImageのColorを白色でAを100にして少し透けるようにしました(もちろん透けないようにしても構いません)。

MaskのShow Mask Graphicにチェックを入れてこのマスク領域のImageを反映させます(チェックをしないとResultTextMaskはマスク領域としてだけ使いImageが表示されません)。

ユニティちゃんRPGのResultPanel子要素のResultTextMaskのインスペクタ

ResultTextMaskの領域は以下のような感じにしました。

ユニティちゃんRPGのResultPanel子要素のResultTextMaskの位置とサイズ

ResultTextMaskを選択した状態で右クリックからUI→Textを選択し、名前をResultTextとします。

インスペクタのAnchor Presetsでtop stretchを選択し、縦は親のResultTextMaskの上、横幅は伸縮するようにします。

Heightを600とします(表示する結果画面のテキストに応じて数値を変更してください)。

Textには適当に文字列を書いて、ResultTextMaskの領域外のテキストが表示されないことを確認します。

Font Sizeを25、ParagraphのAlignmentを左上にし、Colorを白色にします。

ユニティちゃんRPGのResultPanel子要素のResultTextのインスペクタ

ResultTextの位置とサイズは以下のようにResultTextMaskの幅を下に突き破るような感じになります。

ユニティちゃんRPGのResultPanel子要素のResultTextの位置とサイズ

ResultPanelを選択した状態で右クリックからUI→Textを選択し、名前をFinishTextとします。

Textに戦闘を終了すると入力しておきます。

Font Sizeを30、ParagraphのAlignmentを真ん中にし、Colorを赤色にします。

ユニティちゃんRPGのResultPanel子要素のFinishTextのインスペクタ

FinishTextの位置とサイズは以下のようになります。

ユニティちゃんRPGのResultPanelの子要素のFinishTextの位置とサイズ

次に結果は一度に表示できる量を超えた場合にResultTextをスクロールして見れるようにしたいので、スクロールバーを取り付けます。

ResultPanelを選択した状態で右クリックからUI→Scrollbarを選択します。

Anchor Presetsでmiddle centerを選択し、シーンビューで位置やサイズを調整します。

DirectionをTop To Bottomeにし、Valueを1とします。

ユニティちゃんRPGのResultPanel子要素のScrollbarのインスペクタ

ScrollbarゲームオブジェクトのインスペクタのAdd ComponentからUI→Scroll Rectを選択し取り付けます。

Scroll RectのContentにResultTextを設定します。ScrollbarでスクロールするとResultTextが上下に移動するようになります。

Verticalにチェックを入れ上下のみスクロールするようにし、Movement TypeはClampedにしResultTextの範囲内での移動に制限します。

ViewportにResultTextMaskを設定し、Contentが動く範囲の領域を指定します。

Vertical Scrollbarには自身のScrollbarゲームオブジェクトを設定します。

ユニティちゃんRPGのResultPanel子要素のScrollbarのScrollRectの設定

スクロールバーは以下のような位置とサイズになりました。

ユニティちゃんRPGのResultPanel子要素のスクロールバーの位置とサイズ

これで結果画面のUIが出来ました。

FinishTextは最初は表示しないので、インスペクタの名前の横のチェックを外し非アクティブにしておきます。

ここまでの階層は以下のようになります。

ユニティちゃんRPGのResultPanelの階層

ここまで出来たらResultPanelのインスペクタの名前の横のチェックを外し非アクティブにします。

結果画面処理スクリプトの作成

結果を表示するUIが出来たので、戦闘終了時に取得した経験値やお金、アイテムの表示や得た経験値によってレベルアップした際のステータスの表示等を行いたいと思います。

レベルアップデータの作成

レベルアップに必要な経験値を保持しておくデータを作成します。

Assets/RPG/Scripts/Statusフォルダに新しくLevelUpDictionaryとLevelUpDataスクリプトを作成します。

LevelUpDictionaryスクリプトは単にLevelUpDataで使用するキーをキャラクターのレベル、値を経験値としてディクショナリーをインスペクタで表示する為に作ったスクリプトです。

これは以前にItemDictionaryを作った時にやった事と同じです。

LevelUpDataスクリプトはScriptableObjectを継承して作成しアセットファイルとしてデータを設定出来るようにします。

フィールドでLevelUpDictionaryのフィールドrequiredExperienceを宣言し、インスペクタでレベルをキーにし、そのレベルになるのに必要な経験値を値としてインスペクタで設定出来るようにしています。

probabilityToIncreaseMaxHP等のprobability~という名前が付いたものはそのステータスがレベルアップ時に上がる確率です。

minHPRisingLimit等のmin~はレベルアップ時に最低でも上がるステータス量。

maxHPRisingLimit等のmax~はレベルアップ時に上がるステータスの最高値です。

GetRequiredExperienceメソッドは引数で受け取ったレベルがキーに含まれていればそのレベルをキーとする経験値を返し、そのレベルがキーとして見つからなければint値の最大値を返します。

これはそのレベルがキーとして登録されていればレベルアップに必要な経験値を返せるのでその値を返し、見つからなければデータがないのでintの最大値を返してレベルアップしないようにします。

intの最大値を返しているだけなのでintの最大値と同じ経験値を持っていればレベルアップする事になってその後エラーが発生すると思います。

経験値が一定の値を超えていたらレベルアップの処理を行わないような処理をこの後作成するBattleResultスクリプトに入れる必要があるかもしれません。

次にLevelUpDictionaryを反映する為に、Assets/RPG/Editor/SerializableDictionaryスクリプトに処理を追加します。

ItemDictionaryの時と同じでCustomPropertyDrawerを追加します。

Assets/RPG/Data/Status/Allyフォルダに移動し、右クリックからCreateLevelUpDataを選択し、名前をUnityChanLevelUpDataとします。

UnityChanLevelUpDataのデータを入力します。

ユニティちゃんRPGのUnityChanLevelUpDataのデータ

とりあえずレベル1~5までのデータの作成と個々のステータスアップの確率や最低値、最大値の設定をしました。

UnityChanLevelUpDataを選択しCtrl+Dキーで複製し、名前をYujiLevelUpDataに変更しデータを書き換えます。

ユニティちゃんRPGのYujiLevelUpDataのデータ

これでデータが出来ました。

Assets/RPG/Scripts/Status/AllyStatusスクリプトに追加します。

先ほど作成したキャラクターのレベルアップデータをインスペクタで設定出来るようにし、メソッドでそれを取得出来るようにします。

BattleManagerゲームオブジェクトに新しくBattleResultスクリプトを作成し取り付けます。

BattleResultスクリプトはAssets/RPG/Scripts/Battleフォルダに移動させます。

スクリプトが長いので分割して説明していきます。

クラス、フィールド

まずはクラス定義、フィールドを見ていきます。

timeToDisplayは結果画面を表示するまでの待機時間です。

この時間がないと敵を全滅してすぐに結果表示がされてしまいます。

resultPanelは先ほど作成したResultPanelゲームオブジェクトを設定します。

resultTextは先ほど作成したResultTextゲームオブジェクトを設定します。

partyStatusはAssets/RPG/Data/Status/Ally/PartyStatusアセットファイルを設定します。

isDisplayResultはお金の取得等の結果を表示したかどうかです。

isFinishResultは結果を表示し、他のシーンへの遷移が可能となった状態かどうかです。

wonは戦闘に勝利したかどうかです。

ranAwayは戦闘から逃げたかどうかです。

scrollValueは結果をスクロールする値を設定します。

musicManagerは音楽管理スクリプトMusicManagerを設定します(MusicManagerスクリプトは後で作成します)。

Updateメソッド

次にUpdateメソッドを作成します。

Updateメソッドでは現在の状況に応じて処理を行っています。

isDisplayResultがfalseの時は結果をまだ表示していないのでreturnでそれ以降の処理は何もしません。

結果表示がされたらInput.GetAxis(“Vertical”)が0出ない時、つまり↑や↓のキーやコントローラーの上や下を押した時にresultTextの位置を移動させます。

スクロールはY軸方向なのでVector3のYに-Input.GetAxis(“Vertical”) * scrollValueを計算しスクロール値を求めます。

ここでInputの前にマイナスを付けているのは見た目状、下を押した時にresultTextは上に移動させるので反転させた値を設定します。

isFinishResultがfalseの時はreturnでそれ以降の処理はしません。isFinishResultがtrueになっている時はFinishTextが表示されている時です。

FinishTextが表示されている時にSubmit、Action、Fire1ボタンに割り当てられたキーやボタンが押された時にwon(勝利時)、ranAway(逃げた時)の場合はワールドマップシーンに遷移させ、戦闘に遭遇した位置と角度の場所から再開します。

elseの時(敗北時)は最初の村のシーンに遷移させます。

戦闘勝利時の初期処理メソッド

戦闘勝利時には外部からInitialProcessingOfVictoryResultメソッドを呼び出します。

引数で戦闘に参加した全てのキャラクターのリストを受け取ります。

その後StartCoroutineでDisplayVictoryResultメソッドにallCharacterListを引数として渡しコルーチンを使って呼び出します。

戦闘勝利時の実際の処理を行うメソッド

戦闘勝利時の実際の処理を行うDisplayVictoryResultメソッドを作成していきます。

処理が長いのでメソッド内を分割して説明していきます。

経験値やお金、アイテムの取得処理

戦闘に参加した敵から得られた経験値やお金、アイテムを取得する処理を記述します。

DisplayVictoryResultメソッドはコルーチンで呼び出されるメソッドでIEnumeratorを返します。

コルーチンに関しては

Unityでコルーチンを使うと定期的に何らかの処理を行える事が出来るようになります。一見解り辛いけど使い方がわかれば便利かも!?

を参照してください。

最初にyield return new WaitForSeconds(timeToDisplay)でtimeToDisplay秒待機します。

DisplayVictoryResultは勝利時に呼び出されるのでwonをtrueにします。

resultPanelを表示します。

戦闘で獲得した経験値とお金を入れる為の変数を宣言します。

また取得したアイテムとその個数を入れる変数getItemDictionaryも宣言します。

foreachでallCharacterList分の繰り返しを行います。

リストに登録されたキャラクターからCharacterStatusを取得します。

CharacterStatusをEnemyStatusにキャスト出来た場合にその敵から得られる経験値、お金を取得し、earnedExperienceとearnedMoneに足します。

その敵から得られるアイテムディクショナリーをGetDropItemDictionaryメソッドで取得します。

得られたディクショナリーはキーにアイテムデータ、値にそのアイテムを取得出来る確率を設定していますので、ディクショナリーのキー分繰り返しを行ってアイテムを取得出来るかどうかを計算します。

Random.Rangeで0~100の数値でランダムな数値を取得し、そのアイテムの取得率より低い数値であればアイテムを取得したとします。

getItemDictionaryにキーが含まれていればその値を1足し、キーが含まれていなければgetItemDictionaryにキーを登録し、数値を1にします。

その後resultTextに取得した経験値とお金のテキストを足します。

取得したお金をpartyStatusのSetMoneyメソッドで反映させます。

得られたアイテムはランダムに味方パーティーメンバーに分配します。

分配するのはアイテム毎にしているので例えばハーブを5つ取得してもパーティーメンバーの誰かが5つのハーブを手に入れます。

アイテムを取得した数分をメンバーに分割する場合はアイテム数に応じて繰り返す必要がありますね。

キャラクターのレベルアップの処理

キャラクターのレベルアップの処理を先ほどの処理の後に追加します。

レベルアップ時に上がった値を入れておく変数とそのキャラクターのLevelUpDataを入れる変数を宣言します。

partyStatusから味方キャラクターの全てのデータ分繰り返しをします。

キャラクターが変わったらレベルアップ時に上がるステータスをリセットします。

ここで先ほど計算した取得した経験値をそのキャラクターの経験値に反映させます。

1からそのキャラクターのLevelUpDictionaryの最後のデータまで繰り返し、キャラクターの経験値によって今のレベルからどれだけ上がるかを計算します。

キャラクターの経験値が今のキャラクターのレベル+iレベルの時に必要な経験値データを上回っていたら1レベル上げて、上回っていなければbreakでループを抜けます。

ループを抜けたらキャラクターのレベルにレベルを反映します。

キャラクターが上がったレベルlevelUpCountの回数分の繰り返しを行い、ランダム値を計算して、そのステータスの上がる確率以下であればそのステータスの上がる最小値と最大値からランダムを計算し、ステータス変数に足していきます。

levelUpCountが0より大きい時、つまりレベルアップした時はresultTextにレベルアップ情報の表示をし、キャラクターのステータスに上がったステータスを反映します。

ステータスの計算と表示が出来たので、isDisplayResultをtrueにします。

musicManagerのChangeBGMメソッドを呼び出し、戦闘終了時の音楽を流すようにします。

ここでtimeToDisplay秒待機させます。

FinishTextを表示し、isFinishResultをtrueにし結果画面から抜け出せるようにします。

戦闘敗戦時の実際の処理を行うメソッド

敗戦をした時は勝利をした時の獲得した経験値の処理やレベルアップの処理が必要なくなります。

resultTextには『ユニティちゃん達は全滅した。』と表示します。

FinishTextには『最初の街へ』という表示に変更します。

敗戦をした時は味方キャラクターのHPが全て0になっているので、ユニティちゃんのキャラクターステータスを取得し、HPを1にしておきます。

逃げた時の処理を行うメソッド

逃げた時の処理を行うメソッドを追加します。

逃げた時はranAwayをtrueにし、後はやっていることは大体同じです。

戦闘シーンの音楽管理スクリプトの作成

BattleResultスクリプトで結果が表示された後にMusicManagerスクリプトのChangeBGMメソッドを呼んでいるので、そのMusicManagerスクリプトを作成していきます。

MusicManagerスクリプトはAssets/RPG/Scripts/Battleフォルダに作成し、Main Cameraゲームオブジェクトに取り付けます。

audioSourceはMain Cameraに取り付けてあるAudio Sourceコンポーネントを取得し設定します。

BGMAfterTheBattleには結果表示時のBGMに使うオーディオクリップをインスペクタで設定します。

ChangeBGMメソッドが呼ばれたら音声を一旦止めて、loopにfalseを入れ音楽がループしないようにします。

次にAudio SourceのオーディオクリックをBGMAfterTheBattleに変更し、Playメソッドを呼んで再生をします。

ユニティちゃんRPGの戦闘シーンのMainCameraに取り付けたMusicManagerの設定

BGMAfterTheBattleに設定したオーディオクリップはアセットストアでARCHEMY STUDIO MUSICさんの『Free music and SFX collection』をインポートし、その中のFantasy victoryを設定しました。

MusicManagerの作成が終わったのでBattleManagerゲームオブジェクトのBattleResultスクリプトの設定も行います。

ユニティちゃんRPGのBattleResultのインスペクタの設定

戦闘結果画面表示メソッドの呼び出しの追加

戦闘結果画面表示と音楽管理スクリプトが出来たので、次は戦闘結果画面のスクリプトのメソッドを呼び出す処理をBattleManagerスクリプトに追加していきます。

まずはフィールドを追加します。

BattleManagerゲームオブジェクトのインスペクタでBattleResultスクリプトを設定出来るようにしています。

戦闘に勝利した時はBattleManagerスクリプトのDeleteEnemyCharacterInBattleListメソッドで敵が全滅した時なので、enemyCharacterInBattleList.Countが0になった時の最後にbattleResultのInitialProcessingOfVictoryResultメソッドを引数にallCharacterListを渡して呼び出します。

次に戦闘に敗北した時はDeleteAllyCharacterInBattleListメソッドでallyCharacterInBattleListに登録されている数が0になった時なので、その最後でbattleResultのInitialProcessingOfDefeatResultメソッドを呼び出します。

最後に逃げる事が出来た時はGetAwayメソッドで処理をしているので、その中で逃げるのに成功した時の処理の最後にbattleResultのInitialProcessingOfRanAwayResultメソッドを呼びます。

これでBattleResultスクリプトのメソッドを呼び出す処理の追加が終わりました。

戦闘終了後のシーン遷移

戦闘終了後に

勝利していた場合と逃げた場合はワールドマップシーンを読み込んで、敵と遭遇した位置と角度にユニティちゃんを位置させます。

しかし敵と遭遇した時のユニティちゃんの位置と角度がわからないのでその情報を保持しておくようにします。

ワールドマップシーンで敵と遭遇した時にユニティちゃんの位置と角度をSceneMovementDataに保持出来るようにします。

Assets/RPG/Scripts/SceneMovementDataスクリプトに処理を追加します。

まずはSceneTypeにBattleToWorldMapを追加します。

次に敵に遭遇した時のユニティちゃんの位置と角度を保持するフィールドを作成します。

セッターとゲッターを用意します。

これでSceneMovementDataにデータを保持し、それを取り出すことが出来るようになりました。

次は敵と遭遇した時のユニティちゃんの位置と角度を設定する処理を追加します。

ワールドマップシーンのEncountManagerゲームオブジェクトに取り付けているEncountManagerスクリプトを開きます。

フィールドを追加します。

EncountManagerゲームオブジェクトのインスペクタでSceneMovementDataを設定出来るようにします。

Updateメソッド内で敵と遭遇した時の処理をしている個所に処理を追加します。

sceneMovementDataのSetWorldMapPosとSetWorldMapRotメソッドでユニティちゃんの位置と角度を設定する処理を追加しました。

次にAssets/RPG/Scripts/SceneLoadingPositionスクリプトでシーン遷移時のユニティちゃんの位置と角度の処理を追加します。

sceneMovementData.GetSceneType()がSceneMovementData.SceneType.BattleToWorldMapだった時はSceneMovementDataのGetWorldMapPosとGetWorldMapRotメソッドを使って敵と遭遇時のユニティちゃんの位置と角度を取得し、それを設定します。

これで機能が出来ました。

実行して試してみましょう。

上のようになりました。

終わりに

結果の表示は文字列が長くなると見えなくなるのでスクロール出来るようにしましたが、ResultTextの高さ分スクロールするので、結果の文字列が短くても空白部分も含めてスクロールしてしまいます。

あらかじめ画面内に収まるように結果表示をしてスクロールしないようにした方がいい気もしますね・・・・(´Д`)

ユニティちゃんライセンス

この作品はユニティちゃんライセンス条項の元に提供されています

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます