i-school - 2Dタップシューティングゲーム 手順15
 耐久力の値を数字やゲージによって表示する準備ができましたので、まずは最初に、耐久力の値を数字表示する機能を実装します。
以下の内容で順番に実装を進めていきます。


<実装動画 ゲームスタート時に耐久力の現在値と最大値がゲージの上に表示される>
動画ファイルへのリンク


<実装動画 エネミーが拠点に侵入するたびに、耐久力の現在値が更新されて表示される>
動画ファイルへのリンク


手順15 ースクリプトによる耐久力の数字表示の制御処理の実装ー
30.DefenseBaseスクリプトを修正し、ゲーム画面に拠点の耐久力の値を表示・更新する処理を実装する
31.問題点を見つけ、改善方法を考える



 新しい学習内容は、以下の通りです。

 ・SerializeField属性
 ・アタッチとアサインについて
 ・Mathf.Clamp メソッド



31.DefenseBaseスクリプトを修正し、ゲーム画面に拠点の耐久力の値を表示・更新する処理を実装する

1.設計


 先ほどの手順で作成した GaugeSet ゲームオブジェクト群には、耐久力の値(数字)を表示するための役割を持つゲームオブジェクトが含まれています。
このゲームオブジェクトの Text コンポーネントをスクリプトから操作することによって、拠点の耐久力の値をゲーム画面に表示することができますので、その処理を考えます。

 拠点の耐久力の値を表示するタイミングですが、まずは、ゲームがスタートした時点が1つ考えらえます。
また、耐久力の値はエネミーが拠点に侵入するたびに減算されます。そのため、ゲームがスタートした時に表示するほかに
エネミーの侵入によって耐久力の値が更新されるたびに、同じようにゲーム画面の表示も更新して表示する必要があります。



 この処理をどこのスクリプトに記述するかも設計の1つですが、今回は DefenseBase スクリプトに記述していく設計にします。

 記述しなければならないのは、ゲームスタート時に耐久力の現在値と最大値を表示する処理、
および、エネミーが侵入して耐久力の値に変動があったときに、変動後の耐久力の値と最大値を表示する処理になりますので、どの部分に記述すればいいのかを考えていきます。

 画面に文字列を表示するには、Text コンポーネントの管理している、Text プロパティを利用します。
そのため、DefenseBase スクリプトには Textコンポーネントを扱うための変数の宣言を行い、変数内に Textコンポーネント の情報を取得して利用できる状態にする必要があります。

 情報を取得する方法は様々です。
GameObject.Find メソッドを利用しても対象のゲームオブジェクトを探して、Textコンポーネント を GetComponent してもよいですし、
SerializeField属性 を利用して、DefenseBase スクリプトのインスペクターから事前に取得をしておいもよいです。
今回の実装例では、後者の SerializeField属性 を利用していますので、学習しておきましょう。



 現在、durability 変数として現在値の値は DefenseBase スクリプトに用意してありますが、最大値の値となる変数は用意してありません
最大値の値も、durability 変数と同じようにスクリプト内で自由に利用できるようにするため、宣言フィールドに新しい変数を追加します。

 最大値の値は、ゲームスタート時に耐久力の現在値から取得するようにしましょう。
そのため、インスペクターに表示する必要はありませんので、private 修飾子で宣言しておけば問題ありません。
現在値の値を代入する必要がありますので、最大値の変数には、どのような型を用意すればいいかもわかったと思います。


2.DefenseBase スクリプトを修正し、ゲーム画面に耐久力の値を更新して表示する処理を追加する


 設計情報を参考にしながら、どんな情報が必要であるか、それを利用した処理をどこに書けばよいか、考えて日本語のコメントを先に記述してみましょう。

 ゲームのスタートに合わせて行う処理であれば、今までも利用してきた Start メソッドを利用することを考えましょう。
現在 DefenseBase スクリプトには Start メソッドはありませんが、記述していないだけであって、必要があれば再度書き加えていけばよいです。

 視野を広くもって、どんな処理を、どんなタイミングで行いたいか、色々と考えてみてください

 なお、Text コンポーネントをスクリプト内で扱う場合には、using の部分に UnityEngine.UI; の追記が必要になります。


DefenseBase.cs

 <= クリックすると開きます


 スクリプトを修正したらセーブします。

 DefenseBase ゲームオブジェクトのインスペクターを確認し、新しく SerializeField属性 をつけて宣言した変数が表示されていることを確認します。


DefenseBase ゲームオブジェクト インスペクター画像




3.DefenseBaseSet ゲームオブジェクトの設定を行う


 DefenseBaseSet ゲームオブジェクトのインスペクターより、DefenseBase スクリプトに追加された txtDurability 変数に必要な情報をアサインして登録します。

 必要な情報とはすなわち、この変数の型と同じ型の情報(コンポーネント)になります。
インスペクターを確認すると、必要な情報の名前が()の中に表示されています。


DefenseBase インスペクター画像


 
 txtDurability 変数は None(Text) と表示されていますので、現在はまだアサインされている情報がない状態で、
かつアサイン可能な情報は Text コンポーネントであることが分かります。

 アサインできる情報は、ヒエラルキーにあるゲームオブジェクトにアタッチされているコンポーネント
あるいはプレファブになっているゲームオブジェクトにアタッチされているコンポーネントのいずれかに限られます。

 アサインするには、対象となるゲームオブジェクトをインスペクターにドラッグアンドドロップして登録します
この手順を行うことで、そのゲームオブジェクトにアタッチされている該当するコンポーネントが自動的に変数に登録されます。

 txtDurability 変数は、耐久力の現在値と最大値をゲーム画面に表示し、更新していくための情報を扱う変数ですので、
その役割を持っているゲームオブジェクトを選択し、そのコンポーネントをアサインする必要があります

 ヒエラルキーから、txtDurability ゲームオブジェクトを探して、それをこの変数の部分にドラッグアンドドロップして登録してください


DefenseBase ゲームオブジェクト インスペクター画像



 インスペクターの txtDurability 変数の部分が txtDurabilty (Text) と更新されたことが分かります。
これは、txtDurability ゲームオブジェクトの情報のうち、Text コンポーネントがここに登録されている、という形で読みます。
アサインされている情報のインスペクターの読み方も徐々に覚えていきましょう。


 これで設定は完了です。


4.<SerializeField属性>


 変数の宣言に合わせて宣言できる、属性情報と呼ばれるものの1つです。変数の宣言の前に [ ] 付きで書かれた内容が属性情報となります。

 今回利用している属性は SerializeField (シリアライズ・フィールド)という属性情報です。この機能は、インスペクター上に宣言している変数名を表示させる、というものです。

 主に private 修飾子とセットで用いられ、アサインをインスペクター上で可能にするものの、変数の参照先が外部のスクリプトにない(publicの必要がない)場合に利用します。
たとえばButtonコンポーネントやTextコンポーネントといった、インスペクターよりアサインはするものの、その変数の利用先が他のスクリプトにはないようなもの、には利用しやすいです。

 今回はヒエラルキーにある Text 型の情報をアサインできるように宣言しています。


5.<アタッチとアサインについて>


 アタッチアサインという単語があります。これらは似ている言葉ですが、役割は異なります。
正確に把握していないと、先々でつまづいてしまう原因になりますので、しっかりと意味を捉えておきましょう。

 アタッチとは、作成したスクリプト・ファイルやコンポーネントをゲームオブジェクトにドラッグアンドドロップして追加する動作のことです。


<アタッチ>
https://gyazo.com/31b0fb67add402eb9b445c52a45a39b2



 アサインとは、ヒエラルキーにあるゲームオブジェクトをドラッグアンドドロップして
インスペクターに表示されている変数の場所に、ドラッグアンドドロップしたゲームオブジェクトが持つ情報を登録(代入)する、という動作のことです。


<アサイン>
https://gyazo.com/c8ff760295e9ec1c9e7cb04fc7ad620f


 勘違いしやすいのは、スクリプト・ファイル自体をドラッグアンドドロップして、インスペクターにアサインすることはできません


<間違い>
https://gyazo.com/95c74d487fbaad31e0af1695b9766dfa


6.ゲームを実行して動作を確認する


 設定が完了しましたので、ゲームを実行してみましょう。

 まず、ゲームのスタートと同時に、画面の下部分に 100 / 100 と、耐久力の値の現在値と最大値が表示されれば制御成功です。


<実装動画 ゲームスタート時に耐久力の現在値と最大値がゲージの上に表示される>
動画ファイルへのリンク



 続いてエネミーが拠点に侵入した際に、表示される値が 50/ 100 と、耐久力の値の現在値に合わせて表示が更新されれば制御成功です。


<実装動画 エネミーが拠点に侵入するたびに、耐久力の現在値が更新されて表示される>
動画ファイルへのリンク


 このままでも表示の制御は行えていますが、問題点が1つあります。次の手順では問題点の見つけ方と改善方法について学習をします。


31.問題点を見つけ、改善方法を考える

1.問題点を見つける


 拠点の耐久力の値を、エネミーの攻撃力の値よりも低い値に設定してください。攻撃力は 50 ですので、49 以下の値であれば問題ありません。
今回は 30 に設定しています。

 ゲームを実行して、エネミーを拠点に侵入させて、耐久力の値の表示を確認します。


<検証動画 拠点の耐久力よりも大きなダメージを受けた場合>
動画ファイルへのリンク


 スクリプト内で耐久力の値の減算処理の結果がマイナスになっているため、画面の表示のマイナスになって表示されてしまっています。

 耐久力の値の最低値は 0 であることを想定していますので、この挙動は不具合、いわゆるバグになります。


2.改善方法を考える −Mathf.Clamp メソッドの活用−


 問題となる症状はわかりました。さて、問題点はどこにあるでしょうか。それを特定することで改善方法を考えていくことが出来るようになります。

 耐久力の値が減算処理によってマイナスになることは想定されます。常にエネミーの攻撃力が、耐久力の値をピッタリ 0 にしてくれるとは限らないためです。
そうなると、問題となるのは、耐久力の値自体でも、エネミーの攻撃力でもなく、耐久力の値が 0 を下回ったときに、それをそのままにしてしまっている部分にあります。

 減算処理の後に、もしも耐久力の値がマイナスになった場合には、0 にする、という処理を追加すれば改善されるはずです。


<改善動画 マイナス表示にならないように制御する>
動画ファイルへのリンク



 このとき、以下のような処理を記述してもよいですが、この書式ですと、マイナス方向の制限は改善されますが、
プラス方向の制限、つまり、今後、ゲームの処理を実装していく上で、拠点の耐久力の値を回復するような処理が実装された場合には、
耐久力の値が最大値を超えて回復するような場合には、さらに新たな制限文を追加する必要があります

<マイナス方向の制限の例> => プラス方向の制限はない
  if(durability <= 0){
      durability = 0;
  }

 そうなると処理が長くなるだけではなく、その回復処理を追加した場合に、この部分を再度修正し直さなければならなくなります。

 こういった、上限値と下限値を制限したい場合には、Unity には便利なメソッドがあります。今回はそちらを利用して、使い方を学習しましょう。


3.<Mathf.Clampメソッド>


 Mathf 構造体は、Unity が用意している、数学関数の変数やメソッドをまとめてある構造体です。
通常の Math クラスと異なり、戻り値は float 型で用意されています。


参考サイト
Unity 公式スクリプト・リファレンス
Mathf



 Clamp メソッドは、「制御したい指定値を、指定した範囲内の最小値、最大値に収めてくれる(置き換えてくれる)」処理になります。

<メソッドの記法>
  制御したい指定値 = Mathf.Clamp(制御したい指定値, 最小値, 最大値);
 
 このメソッドを利用して、減算処理後の durability 変数の値を制限することが出来ます。
上記のメソッドの書式に、制御したい値を当てはめて処理を組み立ててみましょう。
この処理であれば、上限値も下限値も指定した範囲内の値に収めることが出来る上に、if 文だと、数行分かかっていた処理の式を1行で書くことが出来ます。



 なおMathf.Clampメソッドにはオーバーロードがあり、引数の型は、float型とint型でそれぞれ利用が出来るようになっています。
durability 変数の型は int 型ですので、今回は自動的に int 型を利用しています。


参考サイト
Unity 公式スクリプトリファレンス
Mathf.Clamp


4.DefenseBase スクリプトを修正し、耐久力の値がマイナスになる場合には 0 に制限する処理を追加する


 Mathf.Clamp メソッドを活用して、耐久力の値がマイナスになった場合、0 に置き換えて制限してくれる処理を記述してみましょう。
この処理を書きこみたい場所に日本語のコメントを書いてから、実装を始めてください。


DefenseBase.cs

 <= クリックすると開きます


 スクリプトを修正したらセーブします。


5.ゲームを実行して動作を確認する


 スクリプトを修正したら、ゲームを実行して、耐久力の値がマイナスになった場合、0 の値に置き換えられて制御されているかどうか確認します。


<実行動画 耐久力の値がマイナスにならないように制限する>
動画ファイルへのリンク


 以上で実装完了です。


6.重複している処理をメソッド化する


 Start メソッドと UpdateDurability メソッドには、同じ書式の処理が重複して記述されています。

  // 画面に耐久力の値を 現在値 / 最大値 の形式で表示する
  txtDurability.text = durability + "  / " + maxDurability;

  // TODO ゲージの表示を耐久力の値に合わせて更新


 処理自体が1行であればよいのですが、こういった一連の処理の場合、つまり今回のケースであれば、耐久力の値の表示更新と、ゲージの更新がセットである場合
今後も利用することを考えて、処理の内容をメソッド化しておきます。

 いままで処理があった場所からは、このメソッドを呼び出すようにスクリプトの処理を書き換えておきます。

 今までも何回かメソッド化する処理は実装してきました。
まずは教材を見ずに、自分で処理のメソッド化を行ってみてください。


DefenseBase.cs

 <= クリックすると開きます




 ずいぶんと TODO の部分も増えてきました。このように記述してあると、次に実装したい処理や、残っている処理が見える化できます。
有効に利用しましょう。


 以上でこの手順は終了です。

 次は 手順16 ースクリプトによる耐久力用ゲージの制御処理の実装ー です。