UnityのRPGでワールドマップから戦闘シーンへの遷移を作成する

今回は、RPGゲーム等で主人公が敵と接触したらワールドマップシーンから戦闘シーンへと遷移し、戦闘が終了したら再びワールドマップシーンへと遷移する機能を作成します。

前回が第1弾で、ワールドマップに敵を自動生成し配置する機能を作成しました。

UnityでRPGゲームのワールドマップに敵を自動生成する機能
UnityでRPGゲーム等のワールドマップに敵を自動で敵を配置する機能を作成します。

今回は第2弾ということで、ワールドマップシーンから戦闘シーンへの遷移をした時に、ScriptableObjectを使ってデータを共有していきます。

シーン間のデータ共有に関しては

UnityのScriptableObjectを使ったシーン間のデータ共有
UnityのScriptableObjectを使ってシーンを移動した時にデータを共有出来るようにします。

の記事でやりましたが、その機能を少し改造して使います。

また戦闘シーンは今回は遷移するだけで、戦闘の終了はボタンを押す事で実行出来るようにします。

次回に向けて、カメラのアニメーションと主人公のデータをScriptableObjectから取得し、表示するところまでを作成します。

次回の戦闘シーンの実装はやらないかもしれませんが・・・・・゚ε=ε=ε=ε=(ノ*´Д`)ノ

スポンサーリンク

Mainシーンの作成

まずはシーン間の遷移を管理するMainシーンを作成していきます。

Mainシーンを構成するゲームオブジェクトの作成

他のシーンを管理するMainシーンのヒエラルキー

ヒエラルキー上で右クリック→Create Emptyを選択し、名前をManagementとします。

Managementゲームオブジェクトにはシーン間の移動をする為のスクリプトを設定していきます。

UI→EventSystemを作成し、MainシーンのEventSystemで他のシーンのUIも操作します。

他のシーンでUIを作成してもEventSystemは削除します。

これは、Mainシーンに他のシーンを追加した時にエラーが発生する為で、イベントを操作する時はすべてMainシーンにあるEventSystemを使う事にします。

シーン移動のスクリプトの作成

ManagementゲームオブジェクトにLoadSceneManagerというスクリプトを作成し、設定します。

LoadSceneManagerは画面のフェードイン、フェードアウト、シーンのロード、シーンのアンロードを管理するスクリプトになります。

スクリプトの内容は以前のシーン間のデータ共有の記事とほとんど同じですが、一部違うところがあるので解説していきます。

宣言、Start、FadeAndLoadSceneメソッド

fadeSpeedはフェードのスピード、fadeImageは先ほど作ったImageを設定し、unLoadSceneはアンロードするシーンを入れるフィールドです。

sceneDataはWorld、Battleシーンで使うフェードイメージとボタンを設定するスクリプトを入れておくフィールドです。

Startメソッドは戻り値としてIEnumeratorを付け、Startメソッド内でyield returnを使えるようにし、その処理が終わるまで次の処理に行かないようにします。

Startメソッドが実行されるのは最初にこのスクリプトが登場した時だけなので、シーン間を移動しても再びStartメソッドが実行される事はありません。

その為、Startメソッドで実行するのはWorldという名前のシーン(ワールドマップシーン)をまず読みこんで、読みこんだシーンにあるSceneDataスクリプトを取得します。

FadeAndLoadSceneはシーンを移動する時に呼び出すメソッドで、引数で受け取ったシーン名を読み込んで遷移しますが、その間のフェード処理等も行います。

FadeAndLoadSceneメソッド自体はLoadSceneメソッドをコルーチンで実行するだけのメソッドです。

LoadSceneメソッド

LoadSceneはフェードアウト→新しいシーンのロード→古いシーンのアンロード→フェードインの流れを実行するメソッドです。

まずは戦闘終了ボタンが設定されていればボタンを無効にします。

次に現在のシーンにあるSceneDataを取得し、Fadeメソッドにフェードイメージと引数1を渡してコルーチンで実行します。引数に1が設定されていると先ほど作成したImageのColorのAの値が1(Colorでの255)へと段々変わるので画面全体が暗くなっていきます。

yield returnを付けているので、フェードアウトが終わるまでは次の処理を行いません。

次にDestoryでAudioListenerを削除しています。

これは次のシーンを読みこんだ後に古いシーンをアンロードする仕様にする為、次のシーンでもAudioListnerがあると、一時ですがAudioListenerが2つ存在する事になります。

すぐにアンロードするので最終的に1つしか存在しませんが、コンソールにAudioListenerが2つありますと表示されるので、新しいシーンを読み込む前に削除しています。

次に新しいシーンを読み込む前に、現在のシーンをunLoadSceneに入れておきます。

これはアンロードするシーンを指定する時に使う為です。

次にLoadNewSceneメソッドを呼び出し、新しいシーンを読み込みます。

それが完了したら、UnLoadSceneメソッドを呼び出し、unLoadSceneに入れておいたシーンをアンロードします。

シーンのアンロードが終了したら、戦闘シーンの場合だけフェードインをします。

ワールドマップシーンの時もフェードを使えますが、ワールドマップシーンでのフェード中に主人公が敵と接触すると不具合が発生する為、

フェード中は主人公を動かせないようにする等の対処が必要になってきます。

yield returnを使って、ひとつひとつの処理が完了するまで次の処理を行わないようにしていますが、これはMainシーンに次のシーンを追加し、それから前のシーンをアンロードするという仕様にしている為、画面上二つのシーンが重なって表示されている時があります。

その為、シーンのアンロードが終わるまでフェードインしないようにしています。

やり方としてはフェードアウト→シーンのアンロード&シーンのロード→フェードインの方が適切な気もしますが・・・、うまく出来なかったのでこうなっています。(^_^;)

フェードインが終了した後に、現在のアクティブなシーンがBattle(戦闘シーン)であったらbuttonをアクティブにしています。

これは戦闘シーンに移動し、フェードイン処理が終わってから『ワールドマップシーンに戻る』ボタンを表示する為です。

フェードイン中にボタンが押せると思わぬ不具合が発生します・・・・・(^_^;)

Fadeメソッド

Fadeメソッドはフェード用のImageのアルファ値を現在の値から目的の値へと変化させる処理をしています。

ここは前回の記事とほぼ同じなので説明は割愛します。

LoadNewSceneメソッド

LoadNewSceneメソッドは新しいシーンを読み込む処理をしています。

SceneManager.LoadSceneAsyncの第2引数でLoadSceneMode.Additiveを指定し、Mainシーンに新しいシーンを追加します。

シーンの読み込みが完了したら、最後に読みこんだシーン(新しいシーン)をアクティブにします。

アクティブなシーンがWorld(ワールドマップシーン)であったら、全シーン中からGenerateEnemy(前回作成した敵をワールドマップに自動配置するスクリプト)を探し、InstantiateEnemyメソッドを実行しています。

新しいシーンの読み込みが完了したら、ワールドマップに敵を配置します。

敵の配置をこのタイミングで行っている理由としては、GenerateEnemyスクリプトのStartメソッドで敵を生成する処理を行うとワールドマップシーンが読み込まれるたびに簡単に敵の配置を行えると思ったんですが、Startメソッドでの生成だと、敵のプレハブに設定している他のスクリプトでの処理がうまく出来なかった為です。

UnLoadSceneメソッド

UnLoadSceneメソッドは不用になったシーンをアンロードする処理をしています。

↑ではわたくしの環境の関係上SceneManager.UnLoadSceneを使っていますが、SceneManager.UnloadSceneAsyncが使える方はそちらで書き換えてください。

LoadSceneAsyncと使い方は同じです。

スクリプトの設定とインスペクタ

スクリプトが完成したので、スクリプトを取り付けインスペクタの設定をします。

まずはManagementにLoadSceneManagerを設定します。

Managementのインスペクタの設定

↑のように設定しました。

Mainシーンが完成しました。

ワールドマップと戦闘シーンで共有するデータの作成

次は、ワールドマップと戦闘シーンで共有するデータを作成していきます。

今回ScriptableObjectで作成するデータは、主人公パーティーそれぞれのステータス、敵のステータス、戦闘シーンに入った時のデータです。

味方、敵のステータスはHPやMP、攻撃力といったデータでワールドマップ上での表示や戦闘シーンで使います。

戦闘シーンに入った時のデータは主人公パーティーの並び順、接触した敵のパーティー、敵と接触した時の主人公の位置や角度等を入れます。

キャラクター固有のステータスデータの作成

まずは主人公パーティー、敵のステータスのScriptableObjectを作成します。

ScriptableObjectに関しては

UnityのScriptableObjectを使う
UnityのScriptableObjectを使うと、メモリの節約が出来たり、シーン間の移動でデータを共有するのが簡単になります。この記事では基本だけを記述しています。

を参照してください。

キャラの名前、HP、MP、攻撃力、スピードといったデータを保存出来るようにしておきます。

キャラクターの使用出来るスキル等と言ったデータもあるといいですね。

CreateAssetMenuアトリビュートを取り付けているので、UnityのメニューのAssets→Create→CreateCharacterStatusを選択しデータを作成します。

作成されたデータを主人公パーティー4人分、敵の種類分コピーし名前を設定します。

主人公パーティーと敵データでフォルダ分け

↑のように主人公パーティーそれぞれのステータスと、敵のステータスでフォルダを分けました。

主人公達はEtha1、Ethan2、Ethan3、Ethan4というファイル名で分けてます。わかり辛い・・・(^_^;)

作成したデータを選択するとインスペクタで値が設定出来ます。

キャラクター毎にパラメータを設定

あらかじめ初期値を設定したい項目はここで設定しておきます。

ワールドマップ、戦闘で共有するデータ

次にワールドマップと戦闘で共有するデータを作成します。

主人公パーティーメンバー、戦う敵のパーティーメンバー、主人公のワールド位置と角度を共有するようにします。

KindOfFriendList.FriendListとKindOfEnemyList.EnemyListは

と主人公パーティーメンバーの種類と敵の種類を設定しているだけです。

これの配列をBattleParamとして持っているので、味方のメンバー、敵のメンバーを指定する事が出来ます。

KindOfFriendListとKindOfEnemyListは単なる種類情報を持っているだけのスクリプトで、これらはあとで別のスクリプトで使用します。

BattleParamを作成すると、

戦闘用のデータのインスペクタ

↑のような感じでデータがセットされることになります。

Worldシーンの作成

次にWorldシーンを作成していきますが、前回の自動で敵を配置するシーンとほとんど同じです。

Terrainで地面を作成しレイヤーをField、Terrainの子要素に建物に見立てたCubeを2つ作成しレイヤーをBlock、StandardAssetのEthanのモデルを配置しTag、レイヤーをPlayerに設定します。

キャラクター操作スクリプトの作成

EthanにはCharacterControllerを取り付け、コライダのサイズを調整します。

キャラクター移動スクリプトに関しては

Unityでキャラクターの移動をプログラミングしてみる
Unityで3Dキャラクターモデルを配置し、キャラクターをCharacterControllerの機能を使って移動させるようなプログラミングをしてみます。

等で解説しているので、そちらを参照してください。

その他先ほど作成したBattleParamデータをインスペクタで設定出来るようにします。

これはOnEnableメソッドが実行される度にBattleParamデータから主人公の位置と角度を取得し、設定をする為です。

StartでなくOnEnableにしたのはStartの実行タイミングより早く主人公の位置を決めたかったからです。

SetStateメソッドでキャラクターの状態を変更出来るようにします。

敵と接触した後、フェードアウトする間ずっとキャラクターが移動出来ると困るので、キャラクターをフリーズ状態にして動かないようにします。

主人公パーティー設定スクリプト

主人公パーティーのメンバーを設定するスクリプトを作成し、主人公に設定します。

単純ですね・・・(._.)

これをEthanに取り付け主人公パーティーの並びを設定します。

これで主人公に設定するスクリプトが完成しました。

Worldシーンに配置したEthanの名前をMoveEthanに変更し、スクリプトを設定します。

パーティーの並びを設定

↑のようにMoveCharaにBattleParamデータを設定し、FriendListの引数を4にしてパーティーメンバーの並びを設定します。

今回は番号通りの順番に設定しました。

主人公のAnimatorControllerはIdle(何もしていない状態)とWalk(歩いている状態)の2つを作成し、アニメーションパラメータのSpeed値が0.1以上で歩き、0.1以下で何もしない状態へと遷移を作成し、Animatorに設定します。

敵プレハブの作成

前回の記事で、敵プレハブの作成をしていますが、主人公キャラと接触した時の処理を追加します。

敵のメンバーを指定するスクリプト

敵のメンバーを設定するスクリプトを作成します。

単純に敵と接触したらこれらの種類の敵と戦いますよ、というデータを入れておくだけです。

主人公と接触した時の処理スクリプト

主人公が敵と接触したら戦闘シーンに移動するという処理を作成します。

loadSceneManagerはシーン間の移動を管理するスクリプト、battleParamはワールドマップ、戦闘で共有するデータ、enemyPartyはこの敵と接触した時に戦う敵のメンバーです。

Startメソッドで全シーンからLoadSceneManagerを探します。

また自身に設定したEnemyPartyも取得します。

OnTriggerEnterで接触した相手が主人公だったら主人公の状態をフリーズにします。

その後、共有データであるbattleParamに主人公パーティー、戦う敵のパーティー、主人公の位置と角度を入れておきます。

データを書き換えたら戦闘シーンを読み込みます。

これでスクリプトが出来上がったので敵のプレハブのインスペクタの設定をします。

敵のプレハブはフォルダを分け格納しておきます。

敵のプレハブフォルダ

↑のような感じです。

真ん中のMutantを選択し、インスペクタで設定をします。

Mutantのインスペクタで敵のメンバー等を設定

敵を動かさないので、主人公と接触したかどうかの範囲であるSphereColliderだけ設定してあります。

本来であればCharacterController等を設定し、敵キャラクターもある程度動かした方がいいと思います。

EnemyPartyでは敵のメンバーを設定しています。

このMutantと接触したらこれらの敵と戦うということになります。

敵の種類をランダムに指定出来るようにするにはEnemyPartyスクリプトのStartメソッド等で、ランダム値を使って敵のメンバーを設定するとするといいかもしれません。

ContactではBattleParamを設定しています。

LoadSceneManagerはpublicにする必要はなかったですね・・・(ーー;)

フェードイメージの作成

右クリック→UI→Imageを作成し、RectTransformで縦横Stretchにして画面サイズの大きさにします。

Worldシーンのヒエラルキー

ImageのColorのRGBAを0にし、色は黒で透明にします。

フェード用のImageColorの編集

シーンデータスクリプトの作成

シーンのフェードイメージ、戦闘シーンからワールドマップシーンへと遷移させるボタンを保持するスクリプトを作成します。

Main CameraにGenerateEnemyとSceneDataスクリプトを取り付け設定をします。

WorldシーンのGenerateEnemyとSceneDataの設定

SceneDataのImageには先ほど作ったフェード用イメージ、BattleシーンではないのでButtonには何も設定しません。

これでWorldシーンは完成です。

Battleシーンの作成

やっとこさ戦闘シーンの作成にたどり着きました・・・・゚゚(。´-д-)疲れた。。

戦闘シーンの実装はやらないので、(あれ?やらないかもしれないじゃなくやらないに変わってる)・・・・(;一_一)

戦闘シーンに入った時のカメラワークと主人公パーティーメンバー、敵パーティーメンバーの配置、データの表示をやりたいと思います。

戦闘シーンを作成していきましょう。

戦闘シーンはPlaneで作成した舞台に味方と敵のメンバーを配置するコマンド形式にするとします。

テイルズ系の戦闘シーンがアクションの場合は主人公パーティーと敵パーティーを配置し、敵を全て倒したらワールドマップシーンに戻るように作成すればいいのでこちらの方が簡単かもしれません・・・・。

まぁそれはさておき、Planeで地面を作成します。

戦闘用の地面を作成する

ヒエラルキー上で右クリック→3D Object→Planeを選択し、TransformのPosition、Rotationを全て0にします。

作成したPlaneのマテリアルを草のテクスチャが設定されたマテリアルに変更します。

マテリアルに地面のマテリアルを設定

作成された戦闘用の地面は

実際に作成した戦闘シーンの地面

↑のようになりました。

次に作成した地面に主人公パーティー、敵パーティーを配置する位置と角度を作成します。

ヒエラルキー上で右クリック→Create Emptyを選択し、名前をFriendFieldとしTransformのPositionのXを4にします。

FriendFieldの子要素にCreate Emptyで空オブジェクトを4つ作成します。

名前をFriend1、Friend2、Friend3、Friend4と付け、その番号順で並べます。

主人公パーティーを配置する位置

それぞれのTransformのPositionで、Friend1のZを3、Friend2のZを1、Friend3のZを-1、Friend4のZを-3とし、それぞれのRotationのYを270とします。

これは位置とキャラクターが向く向きを指定しているだけなので、配置したい位置や角度に合わせて調整してください。

次にFriendFieldを選択した状態でCtrl+Dキーで複製し、名前をEnemyFieldにします。

EnemyFieldのTransformのPositionのXを-4に設定します。

子要素の4つをFriendからEnemyに名前を変え、TransformのRotationのYを90に変更します。

これで主人公パーティー、敵パーティーが向かい合う形になります。

カメラワークの作成

戦闘シーンに入ったらカメラが動いて戦闘の舞台をフォーカスするように移動させます。

これにはAnimationの機能を使います。

UnityメニューのWindowからAnimationを選択し、Animationタブを開きます。

Main Cameraを選択した状態でAnimationタブを開き、Createボタンを押します。

AnimationタブのCreateボタンを押してアニメーション作成

ファイルダイアログが表示されるので、BattleCameraという名前を付け保存します。

すると、AssetsフォルダにMain CameraのアニメーションファイルBattleCamera(さきほど付けた名前)とAnimatorControllerであるMain Cameraが作成されます。

カメラのアニメーションとAnimatorControllerが作成される

Animationで作成したアニメーションはAnimatorControllerで制御する事が出来ます。

Main Cameraを選択した状態でAnimationタブを開くと

Animationタブの画面

のようにデフォルトで作成されるBattleCameraクリップのタイムラインが表示されています。

ここでカメラの位置と角度を変更しアニメーションを作成します。

Add Propertyをクリックして、TransformのPositionとRotationを追加します。

アニメーションで変更したいプロパティを追加

↑のPositionとRotationの+をそれぞれ押して追加します。

PositionとRotationのプロパティが追加された

↑のようにプロパティが追加されました。

1:00の部分のプロパティ全体の◇を選択し、位置と角度を調整します。

今回は

カメラの移動前の画像

↑のような位置と角度をせっていしました。

Transformに直に数値を入力すると、

カメラの移動前のTransform

↑のようになります。

次に1:00の部分にある◇を2:00へとドラッグして移動させます。

カメラの移動後は

カメラの移動後の画像

↑のように戦闘の地面を表示させるようにします。

カメラのTransformでは、

カメラの移動後のTransform

↑のようになります。

これでカメラのアニメーションが出来ました。

AssetsフォルダにあるBattleCameraのアニメーションを選択し、Loop timeのチェックを外して1回限りの再生とします。

AnimationのLoop Timeのチェックを外し繰り返し再生しない

次にMain CameraアニメーターコントローラーがMain Cameraゲームオブジェクトに自動的に取り付けられたAnimatorに設定されている事を確認してください。

またAnimatorのチェックが外れいている場合はチェックしておきます。

今回の場合はカメラのアニメーションはBattleCameraだけなのでMain Cameraアニメーターコントローラーは特に変更しません。

これでカメラワークの作成が出来ました。

戦闘用キャラクターの準備

次に戦闘シーンに入ったらBattleParamに設定されている主人公パーティー、敵パーティーのメンバーを戦闘シーンに登場させなくてはいけません。

そこで登場させるキャラクタープレハブを全てResourcesという特殊フォルダに入れて、そこからインスタンス化するようにします。

Resourcesフォルダに戦闘用キャラを入れておく

Resourcesフォルダは特殊フォルダで、そこに入っているゲームオブジェクトはインスペクタに設定しなくてもインスタンス化する事が出来ます。

特殊フォルダについてはUnityのマニュアルを参照してください。

特殊なフォルダー名 - Unity マニュアル
You can usually choose any name you like for the folders you create to organize your Unity project. However, there are folder names that Unity reserves for spec...

キャラクターにはBattleCharaというスクリプトを作成し取り付けます。

自身のキャラクターステータスを保持しているだけのスクリプトです。

BattleCharaに自身のデータを設定

設定したら↑のように自身のキャラクターステータスを設定しておきます。

主人公パーティーステータスの表示UIの作成

次に主人公パーティーのステータスを表示するUIを作成していきます。

主人公パーティーステータス表示領域の作成

ヒエラルキー上で右クリック→UI→Panelを選択し、名前をFriendParamPanelとします。

主人公パーティーステータス表示領域

↑のように画面の右下に表示されるようにサイズ調整します。

主人公パーティーステータスの表示領域インスペクタ

↑がサイズ調整をした後のFriendParamPanelのインスペクタです。

ImageのColorのAを下げて少し透けるようにします。

ゲームビューで見ると、

主人公パーティーステータスの実際の表示

↑のような感じになります。

キャラクター名表示領域の作成

FriendParamPanelの子要素にPanelを作成し、名前をNamePanelとします。

NamePanelにはAdd ComponentからVertical Layout Groupを取り付けます。

NamePanelの子要素にTextを4つ作成し、真ん中に表示されるようにします。

Textを真ん中に表示する設定

↑のようにTextの4つそれぞれで設定します。

NamePanelにVertical Layout Groupを設定したので、Textが上から順に並んで表示されます。

NamePanelのサイズを調整し、以下のようなサイズにします。

主人公パーティー名前表示領域

ヒエラルキーは以下のようになりました。

NamePanelのヒエラルキー

これで名前表示領域の作成が完了しました。

キャラクターHP表示領域とMP表示領域

FriendParamPanelの子要素にPanelを作成し、名前をHPPanelとします。

HPPanelのColorでAを0にし透明にしておきます。

HPPanelの子要素にPanelを2つ作成し、名前をTitle、HPDataとします。

Title、HPDataの子要素にそれぞれ4つTextを作成します。

HPPanelのヒエラルキー

↑のようになります。

TitleとHPDataにはVertical Layout Groupを取り付け、子要素のTextが縦に整列するようにします。

HPPanelをCtrl+Dキーでコピーし、名前をMPPanelとし、位置を調整してHPPanelの右側に移動させます。

MPPanelの子要素のHPDataをMPDataと変更しておきます。

主人公パーティステータス表示領域の完成

↑のような感じでMPPanelの領域が作成出来、主人公パーティーステータスの表示領域の作成が完了しました。

戦闘管理スクリプトの作成

最後に戦闘シーンが開始されたら、キャラクタープレハブをインスタンス化し、そのキャラクターに設定されているBattleCharaスクリプトを取得して名前やHP、MPをUIに表示したり、戦闘の流れを管理する戦闘管理スクリプトBattleManagerを作成していきます。

と言っても戦闘の流れは作らないので、キャラクターのインスタンス化とデータの表示までです。

設定項目

まずは設定項目を見ていきます。

battleParamはScriptableObjectの派生データとして作ったBattleParamを設定します。

friendPartyFieldとenemyPartyFieldは先ほど作ったFriendFieldとEnemyFieldのゲームオブジェクトを設定します。

friendsとenemysは主人公パーティーメンバーと敵パーティーメンバーのゲームオブジェクトを入れておく為のものです。

namePanel、hpPanel、mpPanelは先ほど作成したUIのNamePanel、HPData、MPDataを設定します。

Startメソッド

Startメソッドを見ていきましょう。

まずはSceneManger.SetActiveSceneでBattleシーンをアクティブにしています。

シーン読み込み時にBattleシーンをアクティブにしているはずなので、いらないはずなんですが、これがないとその後ゲームオブジェクトをインスタンス化した時に、

ゲームオブジェクトが前のシーンにインスタンス化されてしまったので、再度Battleシーンをアクティブにしています。

前のシーンにインスタンス化してもすぐさまアンロードされて消えてしまうという事象が発生しました・・・。

そのあと、friendとenemyのパーティメンバー分の配列を確保します。

for文を使ってまずは主人公パーティーメンバーのインスタンス化をします。

Resources.LoadでResourcesフォルダに配置したゲームオブジェクトをインスタンス化する事が出来ます。

Resourcesフォルダのゲームオブジェクトの指定は名前で指定しますので、BattleParamのfriendListから順番にキャラクターの種類を取得しToStringで文字列化し指定しています。

その為、KindOfFriendListスクリプトで指定した列挙型のパラメータの名前と、Resourcesフォルダの中のゲームオブジェクトの名前を一致させておく必要があります。

Resources.Loadの第2引数で型を指定しています。

インスタンス化する位置と角度はfriendPartyFieldの子要素から取得します。

インスタンス化した味方キャラクターのBattleCharaスクリプトからBattleParam共有データにアクセスし、名前、HP、MPを取得し、UIに表示しています。

FriendPartyFieldやUIのHPPanelの子要素等を番号順にしたのはパーティーの順番と合わせる為です。

敵キャラクターもやる事は同じですが、敵のパラメーターは表示しないので、敵のプレハブをインスタンス化しているだけになります。

戦闘シーンからワールドマップシーンへ遷移するボタン用スクリプト

本来であれば必要のない戦闘シーンからワールドマップシーンへと遷移する為のボタン用スクリプトを作成します。

このスクリプトはMain Cameraに取り付けます。

Buttonが押されたらClickButtonメソッドを呼び出すようにします。

Worldシーンの時と同じようにCanvasの子要素にImageを作成しRGBを0、Aを255に設定し真っ黒にします。

また戦闘シーンからワールドマップシーンへと遷移させるボタンを作成し、On ClickにMain Cameraに取り付けたGoToWorldスクリプトのClickButtonメソッドを実行するように設定します。

ワールドマップシーンへと遷移させるボタン設定

buttonは最初は表示させたくないので、インスペクタで名前の横のチェックを外しておきます。

最終的なBattleシーンのヒエラルキーは

Battleシーンのヒエラルキー

↑のようになりました。

Main Cameraの設定は

BattleシーンのMain Cameraのインスペクタ

↑のようになります。

これで機能が完成しました!

機能の確認

主人公パーティーメンバーであるEtan1~4までのデータに名前、HP、MPを設定します。

Ethan1データには名前をEthan1 hpを10、mpを20
Ethan2データには名前をEthan2 hpを20、mpを30
Ethan3データには名前をEthan3 hpを30、mpを40
Ethan4データには名前をEthan4 hpを40、mpを50

を設定しました。

またWorldシーン、BattleシーンのMain CameraにAudio Sourceを取り付け、Audio Clipに音声を設定し、それぞれのシーンのBGMを設定します。

World、BattleシーンにBGMを設定

↑はWorldシーンのMain CameraにAudio Sourceを取り付け、音声を設定した画像です。

BGMなのでPlay On Awakeにチェックを入れ開始とともに再生し、Loopにチェックを入れ繰り返し再生されるようにします。

UnityのメニューからFile→Build Settingsを選択し、Mainシーン、Worldシーン、Battleシーンを追加します。

Mainシーンを最初に読み込ませる為、一番上にドラッグします。

メインシーン、ワールドマップシーン、バトルシーンの追加

シーンの登録が終わったらビルドし、確認してみます。

↑のようになりました。

敵のプレハブ化を試みる回数を増やしたのと、他のキャラクターや建物との距離をほぼ接触距離にして実行しました。

まさに地獄のワールドマップ・・・・、こんな敵だらけの場所歩けませんね・・・・・((((((((((((( ̄▽ ̄;ク、来ルナァッ!!

終わりに

ワールドマップ→戦闘→ワールドマップという流れが出来ましたが、新しいシーンを読み込んでから前のシーンをアンロードしているからか新しいシーンに取り付けたスクリプトのStartメソッドでゲームオブジェクトをインスタンス化すると、前のシーンに作られてしまったりと難しい問題が発生しました。(^_^;)

Mainシーンに追加していかず、LoadSceneModeをLoadSceneMode.Singleにして、完全にシーンを破棄して読み込んだ方が楽だったかもしれません。

これはフェードにも言える事で、フェード用イメージはそれぞれのシーンに配置したUIの手前側に配置する必要がある為、全てのシーンにフェード用イメージを設定し、LoadSceneManagerスクリプトを介してフェードさせています。

個々のシーンで扱うならばそれぞれのシーン用のシーン管理スクリプトを設定すればいいので、FindObjectTypeを使って検索したり、マルチシーンの対応を考えなくてもいいです。

最初はMainシーンにフェード用画像を用意し、全てのシーンのUIを隠す事が出来ると勝手に思って記事の作成まで完了させましたが・・・、サンプル動画を作る時にUIが隠されていない事に気づき、スクリプトの見直し、画像の再作成、記事の文章の修正をする事になりました。( ノД`)シクシク…

Mainシーンにワールドマップや戦闘時のUIも表示するようにすれば個々のシーンにフェード用画像を作る必要はないので、そういう風に作るのもありかもしれません。

あと問題が出そうな点がひとつ、ワールドマップシーンに遷移した時に敵を生成し配置していますが、敵を生成するタイミングは、

LoadSceneスクリプトでワールドマップシーンの読み込みが完了した時です。

その為、GenerateEnemyスクリプトのInstantiateEnemyメソッドで敵をインスタンス化する時に主人公キャラクターを考慮して主人公キャラとの接触範囲外に配置されるのかどうか?

でもシーン読み込みが完了しているということは主人公も当然配置された後だと思うので、問題はないと思うのですが・・・・、たまにワールドマップシーンが読み込まれた後に、すぐ戦闘シーンへと遷移する事がありました。

たぶんこの原因はMoveCharaスクリプトで以前はStartメソッドでキャラクター位置を設定していたんですが、その設定位置が反映される前にGenerateEnemyのInstantiateEnemyメソッドで敵をプレハブ化し配置する処理が起きて、主人公が他の場所にいるということで敵を配置し、その後、主人公位置が決定される為、主人公と敵が重なってしまうのかもしれません。

キャラクターの位置はStartよりも前のタイミングで実行されるOnEnableで行うように変更しました。

今のところ、これで不具合は出ていないですが、なんとも言えないです。

ワールドマップシーンの主人公もプレハブにして、敵を生成する前にインスタンス化するという手もあるかな・・・(‘_’)

戦闘シーン自体も実装しようと思ってたんですが、この記事の機能でだいぶ力を使ってしまった為、戦闘シーンの実装は保留と言う事で・・・・・(ーー;)

参考サイト

UnityライブトレーニングーGameStateー

タイトルとURLをコピーしました