Unityに関連する記事です

 以下の内容で順番に実装を進めていきます。

手順11 −バレットの情報を利用してエネミーを破壊する制御を実装−
22.EnemyController スクリプトを修正し、エネミーのHP(体力)の値を設定し、エネミーを破壊する時の条件を HP が 0 の時に変更する
23.Bullet スクリプトと EnemyController スクリプトを修正し、エネミーのHP(体力)の値をバレットの攻撃力分だけ減算し、0 になったら破壊する処理に書き換える
24.処理を簡潔に書く方法を考える



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

 ・TryGetComponent メソッドと out キーワード宣言



22.EnemyController スクリプトを修正し、エネミーのHP(体力)の値を設定し、エネミーを破壊する時の条件を HP が 0 の時に変更する

1.設計


 エネミーとバレットの当たり判定を実装することによって、無事にエネミーとバレットの双方が破壊されるようになりました。
この手順ではエネミーとバレットに新しい情報を持たせて、それを利用して、破壊する処理を実装していきます。

 まずは最初に、エネミー側に HP(体力)の値を設定し、バレットとぶつかるたびにこの値を減算していって、0 になったときにはじめて破壊されるように、処理の内容を書き換えていきます。

 エネミーの情報は、ゲームオブジェクト自体が持っているわけではありません。Enemy というゲームオブジェクトを、エネミー役として振る舞わせている情報があるはずです。
そう、EnemyController スクリプトです。このスクリプトがアタッチされているために、Enemy ゲームオブジェクトはエネミー役として振る舞うようになっています。

 以上の事から、エネミーの HP という設定値も、この EnemyController スクリプトに追加していくことで、Enemy のゲームオブジェクトに体力という情報があるように設定することが出来ます。



 HP の値はスクリプト全体を通じて利用することになりますので、宣言フィールドに新しく変数を宣言して HP として利用するように考えます。
HP としてやりとりする値は整数が分かりやすいですので、ここでは、int 型の変数として宣言を行いましょう。

 また、public 修飾子をつけて宣言しておくことでインスペクター上にこの hp 変数が表示されます。
つまり、Hp の値を変更するために、スクリプトをその都度いちいち変更しなくてもよいように、インスペクター上から、エネミーの hp の値を変更する出来るように設計しましょう。



 破壊の処理に関しては先ほどの手順で DestroyObjects メソッドとしてメソッド化していますが、このメソッドの処理をそのまま利用してしまうと、バレットと一緒にエネミーも破壊されてしまいます。
このような場合、このメソッドには不要となる処理を切り離して、別の部分に記述するように考えていきます。

 今回、エネミーとバレットがぶつかった際に、常に破壊されてよいのはバレットのみです。
ですので、バレットの破壊処理はそのままにしておいて、エネミーの破壊処理を別の場所で処理するように考えていきます。
 
 またその場合、DestroyObjects というメソッド名も相応しい名称ではなくなりますので、DestroyBullet とメソッド名も変更をします。
メソッド名を変更する場合には、メソッド名の上で右クリックをしてメニューを開き、名前の変更を実行して変更するようにしましょう。
この手順で変更すると、メソッド名だけではなく、このメソッドを呼び出している命令文の名称も一緒に変更になり、非常に便利です。



 では問題のエネミーの破壊処理をどのように考えていくか、です。

 バレットが侵入した際に減算していくことは間違いないでしょうから、まずは、該当の場所にコメントを記述しておきます。
この部分に処理をそのまままとめて書いてもよいですし、先ほどのように、メソッドを作成しておいて、
メソッドの呼び出し命令のみを行い、実際の処理をメソッド内で行うようにしても構いません。

 最初は処理の全文を書いておき、後で見直したときにメソッド化する手法が書きやすいと思います。

 Hp の減算処理ですが、最初は固定値で、一定の値を Hp から減らすように考えてください。
今回はバレットにぶつかったら 15 という値を hp より減らすようにして、この計算結果によって、Hp の値が 0 以下になったときに、
先ほど DestroyObjects メソッドから切り離した、エネミーの破壊処理を実行するようにしましょう。

 コメントはこのようなイメージです。

    // 侵入判定
    private void OnTriggerEnter2D(Collider2D col) {

    // バレットが接触したら
        if (col.gameObject.tag == "Bullet") {
 
            // バレットの破壊処理を呼び出す
      DestroyBullet(col);   // DestroyObjects メソッドから名前を変更

  
            // hp 変数から 15 減らす


            // hp が 0 以下になったら


           // エネミーの破壊処理を行う  
        }
    }

 ロジックを考えてみましょう。計算と制御文が必要になると思います。


2.EnemyController スクリプトを修正し、HP を設定し、バレットとの侵入判定のたびにHPを減らして、0 になったら破壊する処理に書き換える


 宣言フィールドに必要な変数を宣言して、スクリプト内で利用できるようにします。

 DestroyObjects メソッドの名前を DestroyBullet に変更し、バレットの破壊処理のみにします。
メソッド名や変数名を変更する場合には、対象のメソッド名の上で右クリックをしてメニューを表示し、
名前の変更」を選択してください。この方法で変更を行うと、メソッド名だけではなく、このメソッドを呼び出している命令部分も一緒に変更になりますので、
1回の修正で対象となる部分が一括で変更されます。



EnemyController.cs


 スクリプトを修正したら、Enemy ゲームオブジェクトのインスペクターを確認します。
public 修飾子で宣言した情報を表示されていれば問題ありません。


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



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


 Enemy ゲームオブジェクトのインスペクターより、EnemyController スクリプトを確認します。
hp 変数の値をインスペクターより設定可能になっていますので、最初は 30 に設定してみてください。


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



 以上で設定は完了です。


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


 設定が完了しましたので、ゲームを実行してエネミーにバレットをぶつけてみてください。


<実行動画>
動画ファイルへのリンク


 バレットがエネミーのコライダーに侵入するたびに、hp の値が 15 ずつ減算し、その都度、Console ビューに Debug.Log メソッドが実行されて残り Hp が表示されます。
そして、Hp が 0 以下になった際には、エネミーが破壊されるようになりました。


5.EnemyController スクリプトを修正し、処理をメソッド化する


 新しく記述した処理を行うためのメソッドを作成し、Hp の減算処理とエネミーの破壊確認の処理をそのメソッド内で実行するように変更しましょう。
メソッドを書く場所、メソッド名は自由ですが、名前から処理が連想しやすいもの、また、動詞 + 名詞の名称になるように考えてください。
メソッドが完成したら、サマリーを忘れずに書いておいてください。


EnemyController.cs


 修正が終了したら、ゲームを実行して、同じように処理が動いているかを確認してください。


23.Bullet スクリプトと EnemyController スクリプトを修正し、エネミーのHP(体力)の値をバレットの攻撃力分だけ減算し、0 になったら破壊する処理に書き換える

1.設計


 現在はバレット1つにつき、固定の実数値で 15 ずつエネミーの Hp を減算していますが、このままでは、バレットの種類を増やした場合にも同じ値しか減算しない状態です。
そこで固定値ではなく、バレットの攻撃力の分だけ Hp を減算するように処理を変更できれば、バレットの種類によって、エネミーの Hp を減算する値を変更可能になります。

 現在、バレットには攻撃力という情報がありません。かといって、バレットのゲームオブジェクトにも、そのような設定値はついていません
そこで、バレットのゲームオブジェクトにアタッチされている Bullet スクリプトを修正し、このスクリプトに新しく変数を用意して、その値を攻撃力として設定します
エネミーの EnemyController スクリプトに Hp 変数を用意したのと、同じ考え方です。
なぜならば、Bullet ゲームオブジェクトにバレットとしての役割を与えているのが、Bullet スクリプトであるからです。

 設計のポイントとなるのは、変数を作成する際には、どんな目的で、どのように使うのかを、明確に設定してから作成する、ということです。
今回は、バレットの攻撃力として変数を作成する、という明確な目的があり、その用途も、エネミーの hp 変数から減算する、と決めています。

 こうすることによって変数にも役割が与えられて、それを運用することで、処理を実装していくことが可能になります。ここが大事なポイントです。
また、減算を行う、ということですので、双方の変数の型が同じ型同士でなければ減算処理はできません
よって、バレットの攻撃力用の変数の型は自ずと、hp 変数と同じ int 型で作成を行う、という設計に必要な情報も見えてきます。


2.Bullet スクリプトを修正し、バレットに攻撃力を設定する


 宣言フィールドに新しく public 修飾子の bulletPower 変数を宣言して、この値をバレットの攻撃力として利用するようにします。
この値はエネミーの hp 変数の値と計算を行う予定です。hp 変数の型は int 型ですので、計算を行うには双方の型を同じ int 型にする必要があります。


Bullet.cs

 <= クリックしたら開きます


 スクリプトを修正したら、プレファブの Bullet ゲームオブジェクトのインスペクターを確認します。
public 修飾子で宣言した情報を表示されていれば問題ありません。


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




3.プレファブの Bullet ゲームオブジェクトの設定を行う


 Prefabs フォルダ内にある、Bullet ゲームオブジェクトを選択して、インスペクターの一番上の Open Prefab を選択して編集モードにします。
Bullet スクリプトのインスペクター上に bulletPower の値が表示されていますので、先ほどの固定値とは異なる、10 に設定してみましょう。


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



 以上で設定は完了です。


4.EnemyController スクリプトを修正し、バレットの攻撃力の分だけ HP を減らして、0 になったら破壊する処理に書き換える


 この手順では、EnemyController スクリプトにおいて Bullet スクリプトの情報を取得して参照する処理を実装します。

 この処理が必要な理由としては、ぶつかったバレットのゲームオブジェクトやコライダー自体には、攻撃力という設定値の情報がないためです。
あくまでも攻撃力という情報は、バレットのゲームオブジェクトにアタッチされている Bullet スクリプトの情報になりますので、
ぶつかったバレットのゲームオブジェクトの情報を利用して、Bullet スクリプトの情報を取得してはじめて、攻撃力という情報を利用できるようになります。



 バレットがぶつかったとき、バレットのコライダーの情報が、col 変数に代入されています。
この情報を利用して、バレットのゲームオブジェクトの情報を取得することができます。
バレットのゲームオブジェクトの情報を取得することが出来れば、ゲームオブジェクトの情報から、GetComponent メソッドを利用することで Bullet スクリプトの情報を取得できます。
取得する際には、Bullet 型の変数を作成し、その中に Bullet スクリプトを代入して取得するようにしてください。
そうしないと折角情報を取得しても、次の行以降に情報を持ちこすことが出来ません。

 Bullet スクリプトの情報を取得することが出来れば、public 修飾子で宣言している bulletPower 変数の情報を参照することが可能になります。

 このように目的の処理までを順序立てて、必要な情報にたどりつくにはどのような手順を踏んでいけばよいか、そのロジックを考えるようにします。



 Bullet スクリプトの情報は、OnTriggerEnter2D メソッド内で取得している情報ですので、
先ほどメソッド化した UpdateHp メソッドには、この情報がありません。
つまり、Bullet スクリプトの情報を送り届けてあげないと、この情報を UpdateHp メソッドで利用することができません

 このようなときはまた引数の出番になります。UpdateHp メソッドの引数に Bullet 型の変数を用意し、
そして呼び出すときに変数に代入されている Bullet スクリプトの情報を渡すようにします。

 それでは処理のロジックを考えてながら、実装に挑戦してみてください。

<コメント例>
   // 侵入判定
    private void OnTriggerEnter2D(Collider2D col) {

    // バレットが接触したら
        if (col.gameObject.tag == "Bullet") {
 
            // バレットの破壊処理を呼び出す(メソッド名を修正すれば、一緒に修正される)
      DestroyBullet(col);


            // 侵入してきたコライダーのゲームオブジェクトに Bullet スクリプトがアタッチされていたら取得して Bullet 型の変数に代入


           // bullet 変数に Bullet スクリプトが代入されているなら

            
            // HPの更新処理とエネミーの破壊確認の処理を呼び出す(UpdateHp メソッドに送る引数の情報を追加)
                UpdateHp();
            }
        }
    }

    /// <summary>
    /// Hpの更新処理とエネミーの破壊確認処理
    /// </summary>
    private void UpdateHp()   // <=  受け取る情報用の引数を追加
    {

        // hpの減算処理(固定値を受け取った情報から利用する形に変える)
        


        if (hp <= 0) {
            hp = 0;

            // このゲームオブジェクトを破壊する
            Destroy(gameObject);
        } else {

            Debug.Log("残り Hp : " + hp);
        }
    }
}



EnemyController.cs



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


 修正が完了しましたので、ゲームを実行し、先ほどと同じようにエネミーにバレットをぶつけてみてください。
先ほどの固定値の値ではなく、バレットのゲームオブジェクトの Bullet スクリプトに設定した攻撃力(bulletPower 変数)分ずつ Hp が減算していれば制御成功です。
bulletPower 変数の値を変更して、何回か試してみてください。


<実行動画>
動画ファイルへのリンク


 以上のことから、スクリプトを通じて、別のスクリプトの情報を利用することがわかりました。
この処理が基本的な処理になりますので、しっかりとイメージして、処理の流れをつかんでおいてください。


24.処理を簡潔に書く方法を考える

1.設計


 新しく OnTriggerEnter2D メソッドに追加した処理の部分を簡潔に記述する方法がありますので、学習します。

<対象の処理>
  Bullet bullet = col.gameOnject.GetComponent<Bullet>();

  if(bullet != null) {
      UpdateHp(bullet);
  }

 まずこの処理の必要性ですが、万が一、GetComponent メソッドを実行した結果、Bullet スクリプトが取得できなかった場合、bullet 変数には情報が代入されず null の状態になります。
そのため、次の行の if 文による null の確認がないと、null の変数を利用とした時点でエラーが発生してゲームが停止してしまいます。

 このような確認の方法を null チェックといい、変数に値が代入されていることを確認した上で処理を行うことが重要になっています。

 今回学習する TryGetComponent メソッドは、GetComponent メソッドの処理と if 文の null チェックを一緒に行ってくれるメソッドですので、こちらを利用して処理を簡潔にしています。
そのためには、この処理がどのように動いているのかを把握しておく必要があります。


2.<TryGetComponent メソッドと out キーワード宣言>


 Unity2019.2以降に追加されたメソッドです。処理結果として bool 型で戻り値を返してくれます。
このときの処理結果というのは、指定したコンポーネントの型の取得を行い、それが取得できればtrue、取得できなければfalseが戻ります

 また out キーワードによる宣言があります。
 out キーワード宣言を行うと、out を付けた引数で指定した変数はメソッド内で必ず結果が入ることが保証されるものです。
そのため、処理結果の戻り値が true の場合には必ず、この out の後に宣言した変数内に型が代入されます

if(col.gameObject.TryGetComponent(out Bullet bullet)) {

 今回はこのような処理として利用しています。col 変数の持つ collider 情報から gameObject(つまりバレットです)へとアクセスし、その gameObject に対して TryGetComponent メソッドを実行しています。

 out以降にはゲームオブジェクトから取得したい型と変数を宣言します。今回は、 Bullet 型bullet 変数を用意しておきます。

 もしもこの TryGetComponent メソッドの処理結果が true であるならば、つまり、ゲームオブジェクトに Bullet スクリプトがアタッチされているのであれば、
out として用意した bullet 変数に Bullet スクリプトの情報が代入されて、さらに、if 文内に処理が実行されます
また if 文内の間はこの bullet 変数が使用できることになります。(スコープがif文ブロック内であるためです

 TryGetComponent メソッドの処理結果が false の場合には Bullet スクリプトの取得ができなかったため、bullet 変数は null のままで、false が結果として戻り、
このif文内の処理は実行されないままで終了します

 つまり、先ほどまで、処理を分けて記述していた内容を、1つの処理としてまとめて記述することが出来ている事が分かります。


 なお TryGetComponent メソッドには複数の書式があります。こちらは下記のリファレンスを参照してください。

参考
Unity公式スクリプトリファレンス
Component.TryGetComponent
https://docs.unity3d.com/ScriptReference/Component...


3.EnemyController スクリプトを修正し、if 文の処理を TryGetComponent 処理に書き換えて処理を簡潔化する


 該当の処理を、TryGetComponent メソッドと out キーワードを利用した処理を書き換えて簡潔に記述します。
処理の内容を理解した上で書き換えていきましょう。


EnemyController.cs



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


 処理を簡潔に書き替えただけですので、同じように動くはずです。
 ゲームを実行して確認をしておいてください。

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

 次は 手順12 ープレイヤーの拠点の実装ー です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



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

管理人/副管理人のみ編集できます