おっさんのUnity入門 2Dオブジェクトで弾を飛ばして敵を倒す(オブジェクトの削除とレイヤーの使い方)
弾となるオブジェクトを追加して敵オブジェクトを撃退する動作を実装します。
【追加するオブジェクト】
- Bullet (スプライトをSceneへ追加して作成)
Bulletの配置位置は敵オブジェクトに当たるくらいの高さに設定します。
【BulletのInspector設定】
【追加するComponent】
- Bullet(弾を制御するスクリプト)
- Box Collider 2D(Add Component > Physics 2D > Box Collider 2D)
- Rigidbody 2D(Add Component > Physics 2D > Rigidbody 2D)
Hierachyにある弾オブジェクトBulletは、後で量産して発射できるようにPrefab(プレファブ)化しますが、編集の都合でひとまずSceneへ配置した状態で編集します。
Rigidbody 2DのGravity Scaleに微小な数値を指定して徐々に弾が下降するようにします。
【Bullet.cs】
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullet : MonoBehaviour { // 弾オブジェクト(Inspectorでオブジェクトを指定) [SerializeField] // Inspectorで操作できるように属性を追加します private GameObject bullet; // 弾オブジェクトのRigidbody2Dの入れ物 private Rigidbody2D rb2d; // 弾オブジェクトの移動係数(速度調整用) float bulletSpeed; void Start () { // オブジェクトのRigidbody2Dを取得 rb2d = GetComponent<Rigidbody2D> (); // 弾オブジェクトの移動係数を初期化 bulletSpeed = 10.0f; } void Update () { // 弾オブジェクトの移動関数 BulletMove (); } // 弾オブジェクトの移動関数 void BulletMove () { // 弾オブジェクトの移動量ベクトルを作成(数値情報) Vector2 bulletMovement = new Vector2 (1, 0).normalized; // Rigidbody2D に移動量を加算する rb2d.velocity = bulletMovement * bulletSpeed; } // ENEMYと接触したときの関数 void OnCollisionEnter2D (Collision2D collision) { // ENEMYに弾が接触したら弾は消滅する if (collision.gameObject.tag == "enemy") { Destroy (gameObject); } } }
弾オブジェクトが敵オブジェクトと接触すると敵オブジェクトを画面の外まで押し出してしまうので、敵オブジェクトに接触したら消滅するようにDestory関数を使います。
【Bullet.csのBulletオブジェクトにHierachyのBulletを指定する】
Bulletフォームの右横にある〇をクリックしてBulletを指定します。
弾オブジェクトが配置位置から直進します。
敵オブジェクトと接触するとSceneから削除されます。
【弾オブジェクトの量産化】
プレイヤーオブジェクトの位置から弾オブジェクトを発射できるように改良しています。
【弾オブジェクトのプレファブ化】
スクリプトから動的にオブジェクトを生成する場合は、プレファブと呼ばれるオブジェクトのテンプレートを呼び出すことで実現できます。
プレファブを作るには、HierachyにあるオブジェクトをProject内の任意の場所へドラッグ&ドロップします。管理しやすいように予めProject直下にPrefabsというフォルダを作っておきます(Project > Create > Folder)。
プレファブ化が完了するとHierachyにあるオブジェクト名が青い表示に変化します。
※HierachyにあるBulletは必要なくなったので、右クリック > Delete で削除します。
※発射されたときの弾オブジェクトの生成位置を発射位置の中心になるように初期化しておきます。
Prefabs > Bullet を選択して Transform > Position「X:0 Y:0 Z:0」へ設定しておきます。
【弾オブジェクトを発射するための設定】
弾オブジェクトを発射するためのキーの設定をします。
Edit > ProjectSettings > Input でキー入力ウィンドウを表示します。
Axes > Fire1 > Positive Button へ「a」を指定して、「a」キーをタイプするたびに弾オブジェクトが発射されるようにします。
【弾オブジェクトとプレイヤーの衝突回避設定】
弾オブジェクトはBox Collider 2Dが設定されているため、プレイヤーオブジェクトとも衝突することになります。現在の設定では、プレイヤーオブジェクトの中心から発射されるためプレイヤーも発射した弾にはじかれてしまいます。
Unityにはレイヤーというオブジェクトが配置される層の重なりを設定することができる機能があります。別レイヤーに配置されたオブジェクト同士は衝突しなくなるためこれを利用します。
【レイヤーの追加設定】
Edit > ProjectSettings > Tags and Layers でレイヤーを設定するウィンドウを表示します。
Layers >「User Layer 8 : Player」「User Layer 9 : Bullet」それぞれ入力します。
【レイヤーと物理動作の設定】
Edit > ProjectSettings > Physics2D でレイヤー同士の衝突動作を設定します。
※Physics ではなくPhysics2Dであることに注意
縦軸Bullet 横軸Playerの重なっている部分のチェックボックスを外すと物理的な衝突が発生しなくなります。
※コライダーによる衝突判定(OnCollisionEnter2D)は物理的衝突動作を解除した後も有効です。
【プレイヤーに発射用スクリプトを追加する】
衝突関係の設定ができたので、プレイヤーに弾オブジェクトを発射するためのスクリプトを追加します。
【PLAYER_GREENオブジェクトに追加するComponent】
- PlayerBullet(弾を発射するスクリプト)
プレイヤーを基準として弾オブジェクトが右方向へ発射されるようになります。
【PlayerBullet.cs】
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerShot : MonoBehaviour { // InspectorでPrefab化したBulletを指定する [SerializeField] private GameObject bullet; void Update () { // 弾オブジェクトを生成して飛ばす関数を呼び出す ShotAction (); } // 弾オブジェクトを生成して飛ばす関数 void ShotAction () { if (Input.GetButtonDown ("Fire1")) { Instantiate (bullet, transform.position, transform.rotation); } } }
【PLAYER_GREENのInspectorでプレファブ化したBulletを指定する】
Hierachy > PLAYER_GREEN > Inspector > Bullet (Script) > Bullet のフォーム右側にある〇をクリックしてPrefabs内のBulletを指定します。
キーボードの「a」をタイプすると弾オブジェクトが発射されるようになりました。
現時点では敵オブジェクトに当たらない弾オブジェクトはメモリ上にずっと存在していることになります。撃ち続けるとどんどんメモリを消費してしまうため、一定時間後に自動的にメモリ上から削除するように弾オブジェクト移動用スクリプトBullet.csを修正します。
【Bullet.cs】
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullet : MonoBehaviour { // 弾オブジェクト(Inspectorでオブジェクトを指定) [SerializeField] // Inspectorで操作できるように属性を追加します private GameObject bullet; // 弾オブジェクトのRigidbody2Dの入れ物 private Rigidbody2D rb2d; // 弾オブジェクトの移動係数(速度調整用) float bulletSpeed; void Start () { // オブジェクトのRigidbody2Dを取得 rb2d = GetComponent<Rigidbody2D> (); // 弾オブジェクトの移動係数を初期化 bulletSpeed = 10.0f; // 出現から3秒後に弾オブジェクトを消滅させる(メモリの節約) Destroy (gameObject, 3.0f); } void Update () { // 弾オブジェクトの移動関数 BulletMove (); } // 弾オブジェクトの移動関数 void BulletMove () { // 弾オブジェクトの移動量ベクトルを作成(数値情報) Vector2 bulletMovement = new Vector2 (1, 0).normalized; // Rigidbody2D に移動量を加算する rb2d.velocity = bulletMovement * bulletSpeed; } // ENEMYと接触したときの関数 void OnCollisionEnter2D (Collision2D collision) { // ENEMYに弾が接触したら弾は消滅する if (collision.gameObject.tag == "enemy") { Destroy (gameObject); } } }
一定時間(この場合3秒)後に自動的に生成されたBulletオブジェクトが削除されました。
【敵オブジェクトの削除】
続いて敵に体力を設定して体力が0になったら消滅するように改良していきます。
【敵オブジェクトに敵の体力を管理するスクリプトを追加します。】
【EnemyStatus.cs】
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyStatus : MonoBehaviour { // 敵の体力の入れ物 [SerializeField] private int enemyArmorPoint; void Start () { // 敵の体力を初期化 enemyArmorPoint = 3; } // 弾オブジェクトと接触したときに呼び出される関数 void OnCollisionEnter2D (Collision2D collision) { // もしもtagがbulletであるオブジェクトと接触したら if (collision.gameObject.tag == "bullet") { // 敵の体力が0以上だったら if (enemyArmorPoint > 0) { // 敵の体力を1削る enemyArmorPoint -= 1; } else { // 敵の体力が0になったら敵オブジェクトを消滅させる Destroy (gameObject); } } } }
【弾オブジェクトへタグを追加する】
敵オブジェクトが弾オブジェクトを認識できるようにするためbulletというタグを追加します。
Prefabs > Bullet > Inspector > Tag > Add Tag ... を選択してタグ追加ウィンドウを表示します。
「bullet」と入力して「save」をクリックします。
bulletが追加されて使用可能になりました。
Prefabs > Bullet > Inspector > Tag > bullet を選択します。
【動作確認】
敵の体力が0になってシーンから削除された。