i-school - 複数用意したプレイヤーキャラクターをボタンで変更する

設計とロジックについて


 キャラ変更用のボタンを画面上に設置し、そのボタンを押すと操作するプレイヤーキャラクター(以下、キャラ)を変更できるようにします。

https://gyazo.com/2cfced95fb0da5a165983070783ccada


 まず現在使用中のキャラの情報を、キャラの通し番号とクラスで保持できるようにしておきます。

 使用中のキャラの番号を用いて、変更先となるキャラの番号を照合し、キャラの変更を行います。
キャラの変更と同時に、使用中のキャラのクラスを上書きして、変更になったキャラと操作できるキャラが異なることを防ぎます。
 
 主な手法としましては、始めからキャラをヒエラルキーに設置しておいてSetActiveメソッドを使ってキャラを切り替える方法と、キャラをインスタンスする方法がありますので
今回はインスタンスする方法で実装を行います。

ボタンを押す => 変更先となるキャラを設定する => インスタンスする => 変更元のキャラを破棄する => カメラに変更先のキャラを登録する


以上が主な処理の流れになります。 

実装の手順について


 以下の順番で実装を行っていきます。

1.キャラ変更用のボタンを2つ作成する
2.GameDataスクリプトを修正する
3.DataBaseManagerスクリプトを修正する
4.UIManagerスクリプトを修正する
5.MainCameraContollerスクリプトを修正する
6.ChangeCharactersスクリプトを新しく作成する


 新しい技術としては、大きく以下のようなものがあります。

・指定したコルーチンメソッドが終了するまで、その次の処理を行わないように待機させる方法
・ボタンクラスにスクリプトから引数付のコルーチンメソッドを登録する方法(ヒエラルキーから直接ボタンに設定しないようにする方法)
・GameObject型ではなくて自作クラスを用いてプレファブを生成して変数に代入して使用する方法
・ボタンの活性化/非活性化の方法

1.キャラ変更用のボタンを2つ作成する


 以下の画像を参考にして、Canvas内にボタンを2つ作成してください。どちらもキャラ変更に使用するものです。
変更するキャラを番号で管理する処理のため、1つボタンは番号を1つ進める処理、もう1つのボタンは番号を1つ戻す処理を登録して使用します。



2.GameDataスクリプトを修正する

※ 以下の各スクリプトは、特別記載がない限りは今回の部分で使用する内容のみの追加掲載になります。ご自分のスクリプトに適宜追加して利用してください。

 現在使用しているキャラの通し番号と、キャラの情報(クラス)を管理するための変数をそれぞれ用意します。
どちらもpublic修飾子の変数ですが、InitializePlayerメソッドにて、それらに初期設定を行っていますので、インスペクターで指定する必要はありません。

GameData.cs




3.DataBaseManagerスクリプトを修正する


 ゲームで操作できるキャラのプレファブを配列に用意しておきます。
この配列の要素数の番号と、GameDataで用意した通し番号の変数とを紐づけて、操作できるキャラをインスタンスします。

DataBaseManager.cs


 修正が完了したら、DataBaseManagerゲームオブジェクトのインスペクターを確認します。
追加した配列のCharas変数が表示されていますので、こちらのSizeを 0 から、ゲーム中に登場させるキャラの数に変更します。
その後、それぞれの値に各キャラのプレファブをPrefabsフォルダからドラッグアンドドロップしてアサインします。



4.UIManagerスクリプトを修正する


 UIManagerでは、キャラ変更ボタンの管理を行います。ボタンを押した際に、最後に作成するChangeCharactersクラスのメソッドを呼び出して
キャラ変更へとつなげる役割を持っています。

 キャラ変更用の2つのボタンについては、いずれかを選択した時点で、キャラ変更が終了するまでの間、両方のボタンを押せないように制御を入れています。

「キャラ変更が終了するまで」という状態は、bool型などの変数を用意して管理することもできますが、今回はOnClickChangeCharaメソッドをコルーチン化し、
キャラ変更を行う処理(ChangeCharactersクラスのChangeCharaメソッド)の呼び出しを yield return 付のStartCoroutine処理にすることによって、この処理が終了するまで
下の処理にはいかないように制御しています。

またボタンによって呼び出されるOnClickChangeCharaメソッドはコルーチンメソッドであるため、Startメソッド内で、それぞれのボタンにメソッドと引数を登録しています。
(UnityEditorのButtonコンポーネントにあるOnClickイベントは使わずに、スクリプトから呼び出すメソッドを設定します)

UIManager.cs


 修正が完了したら、UIManagerゲームオブジェクトのインスペクターを確認します。
新しく変数が3つ追加されていますので、Btn〜の方には、【1】で用意した各ボタンをヒエラルキーからドラッグアンドドロップしてアサインします。(同じ名前になるようにアサインしましょう)

 もう1つのChangeCharactersの方はまだ作成していませんので、こちらは作成してからアサインしてください。


<補足>

 InactivateCharaChangeButtonメソッドのように、複数回呼び出される可能性のある処理は、このようにメソッド単位でまとめて制御するようにします。
bool型の引数を用意することで、設定の切り替えを動的に行えるようにしています。isSwitch = trueならば、各ボタンのinteractableもtrueになる、というようにです。

 このような制御を行うことで、true/falseのために、2つのメソッドを作る必要がなくなります。

 今後も、スクリプト内の処理をすべて書いてからでもよいので、重複している処理はないか、あるのであれば、それはメソッドに処理をまとめて管理した方が利便性が高くないか、
という観点でコードを確認してみてください。そのようにコードを読み直すことで、さらに書き直すことができればスキルが上達します。

5.MainCameraContollerスクリプトを修正する


 StartメソッドでのPlayerの検索方法をTagに変更しています。
キャラが変更されるということは、カメラの追従対象を変更しなければなりません。
そのため、SetUpCharaメソッドを用意し、キャラの変更に合わせてカメラの追従対象のキャラも変更を行うようにします。

 カメラの追従処理はUpdateメソッドにおいて行われています。そのため、一時的であってもキャラがいない状態が出来てしまう(chara変数にPlayer情報がなくなる)と
追従対象がなくなるため、エラーが発生してゲームが停止します。これを、Chara変数にPlayerが取得出来るときだけUpdate内の追従処理を行うことで回避しています。

MainCameraController.cs


6.ChangeCharactersスクリプトを新しく作成する


 このスクリプトは新しく作成します。各キャラ変更のボタンから呼び出されるメソッドです。
処理の詳細はコメントを確認してください。

ChangeCharacters.cs


 作成した後はヒエラルキーに Create Empty で新しいゲームオブジェクトを作成し、名前を ChangeCharacters に変更して
作成した ChangeCharacters のスクリプトをアタッチします。その後、まずはUIManagerゲームオブジェクトのインスペクターを確認し、ChangeCharacters変数にアサインします。


 続いて、ChangeCharacters ゲームオブジェクトのインスペクターを確認してください。アサイン情報が2つ表示されます。




 1つはMainCameraControllerです。こちらは MainCamera ゲームオブジェクトにアタッチされていると思いますので、それをドラッグアンドドロップしてアサインします。

 もう1つはキャラ変更ボタンを押した後の待機時間の設定です。どちらかのキャラ変更ボタンを押した場合、ここで設定した時間だけ両方のボタンが押せなくなります。
値は適宜調整してください。


 ゲームを実行して、それぞれのキャラ変更ボタンを押してみてください。キャラが切り替わり、カメラも追従するようになっていれば完成です。