【Unity】2Dシューティングゲームの作り方⑦:プレイヤーの当たり判定とリトライ処理

Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、Unityを使った2Dシューティングゲームの作り方7回目として、プレイヤーが攻撃を受けてリトライする処理について紹介しています。

前回、敵が移動して攻撃してくる処理を作っていきました。

今度は、敵からの攻撃がプレイヤーに当たった際の処理を作っていきます。

プレイヤーに弾が当たる仕組みは、敵と同じく当たり判定処理を作ることでできますが、プレイヤーに当たった後に最初からゲームを始めるようにするためには、シーンを読み込ませていく必要があります。

そこで、プレイヤーに弾が当たる当たり判定処理と、シーンを読み込むリトライ処理までをまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

敵の弾にColliderコンポーネントを付ける

まずは、敵の弾のオブジェクトに当たり判定を付けるため、Colliderコンポーネントを設定していきましょう。

Prefab化してあるEnemyBulletを選択して、インスペクターウィンドウの「Add Component」をクリックします。

Physics 2Dの中の「Circle Collider 2D」を選択します。

Prefabオブジェクトなので、インスペクターウィンドウの上のOpenを押して、オブジェクトの編集を開きます。

操作ツールでColliderの編集ボタンを押して、大きさや範囲をマウスで調整していきます。

Colliderの範囲が決まったら、インスペクターウィンドウのCircle Collider 2Dの項目で、「Is Trigger」にチェックを入れておきます。

これで、敵の弾のオブジェクトにColliderコンポーネントを付けることができました。

なお、Colliderコンポーネントについては以下の記事でも解説していますので、参考にしてみてください。

プレイヤーにColliderとRigidbodyを付ける

次に、プレイヤーのオブジェクトにColliderコンポーネントRigidbodyコンポーネントを付けていきます。

まず、playerを選択してインスペクターウィンドウの「Add Component」を押して、Physics 2Dから「Polygon Collider 2D」を選択します。

そして、シーンビューのCollider編集ボタンを押して、プレイヤーのオブジェクトに合わせてコライダーの範囲を設定していきます。

範囲の設定が終わったら、先ほどの弾のオブジェクトと同じくPolygon Collider 2Dの項目にある「Is Trigger」にチェックを入れておきます。

次に、Rigidbodyコンポーネントを付けるので、もう一度インスペクターウィンドウの「Add Component」を押して、Physics 2Dから「Rigidbody 2D」を選択します。

Rigidbodyを付けると、重力機能がデフォルトでオンになっているので、Rigidbodyの項目からBody Typeを「Kinematic」に変更しておきます。

これでプレイヤーのオブジェクトに、ColliderコンポーネントとRigidbodyコンポーネントを付けることができました。

なお、Rigidbodyコンポーネントについては、以下の記事でも解説していますので、参考にしてみてください。

プレイヤーにダメージを与えて消去する処理

それぞれのオブジェクトに当たり判定を付ける設定が完了したので、次はプレイヤーに弾のダメージを与える処理を行っていきます。

今回は、プレイヤーに一度弾が当たったら消去するといった処理にしたいので、HPなどの変数は作らずに書いていきます。

プレイヤーの処理を決めるスクリプトであるPlayerControllerに、以下のスクリプトを書いていきます。

using UnityEngine;

public class PlayerController : MonoBehaviour
{

// ~~~~~ 一部省略 ~~~~~

    void OnTriggerEnter2D(Collider2D collision) // 他のオブジェクトとの当たり判定の処理
    {
        if (collision.gameObject.name == "EnemyBullet" ||   // 敵の弾に当たった場合
            collision.gameObject.tag == "Enemy")            // 敵のオブジェクトに触れた場合
        {
            this.gameObject.SetActive(false);   // オブジェクトを消去する
        }
    }
}

8行目で、OnTriggerEnter2Dメソッドを使って当たり判定の処理を書いていきます。

敵のオブジェクトと敵の弾のオブジェクトと当たった時にダメージを与える処理にしたいので、10と11行目でif文を使って敵のオブジェクトと敵の弾のオブジェクトに当たったかどうかを条件指定しています。

そして、当たり判定があった場合は、プレイヤーを消去させるようにしたいので、13行目でSetActive関数を使ってfalseでプレイヤーを非表示にさせています。

これで実際にゲームを実行してみると、

敵の弾に当たるとプレイヤーが消えるという処理を作れました。

敵の弾を破壊する処理

先ほどプレイヤーが倒れる処理を作りましたが、プレイヤーの弾が敵に当たる際の処理と同じく、敵の弾のオブジェクトが当たったら消えるという処理を加えていきます。

敵の弾の処理を作っているのは、EnemyBulletMoveというスクリプトだったので、これに以下のスクリプトを追加していきます。

using UnityEngine;

public class EnemyBulletMove : MonoBehaviour
{

// ~~~~~ 一部省略 ~~~~~

    void OnTriggerEnter2D(Collider2D collision) // 他のオブジェクトと当たった場合の処理
    {
        if (collision.gameObject.name == "player")  // オブジェクト名が「player」の場合
        {
            Destroy(gameObject);    // 弾を破壊する処理
        }
    }
}

8行目でOnTriggerEnter2Dメソッドで当たり判定の処理を作り、10行目で当たった相手のオブジェクトが「player」の時にだけ条件を絞っています。

そして、12行目でDestroyメソッドを使い、敵の弾を破壊する処理を作っています。

これでもう一度ゲームを実行してみると、

ちゃんと弾が消えるようになりました。

プレイヤーがいなければ弾を発射しない処理を加える

敵の弾がプレイヤーに当たり、破壊されるようになりましたが、プレイヤーがいなくなった後も敵の弾が発射されてしまっています。

また、プレイヤーがいないことで、プレイヤーの座標取得ができず、弾が移動されないことになってしまっています。

そこで、プレイヤーがいなくなった場合は、敵が弾を発射しないという処理を加えていきたいと思います。

敵が弾を発射する処理を行っているのは、EnemyShootのスクリプトだったので、このスクリプトに対して以下のように変更を加えていきます。

using UnityEngine;

public class EnemyShoot : MonoBehaviour
{
    public GameObject enemyBullet; // GameObject型の変数を宣言する
    GameObject player;  // playerを参照する
    float span = 2.0f;  // 弾を撃つ間隔を指定
    float delta = 2.0f; // 加算用の変数を宣言

    void Start()
    {
        player = GameObject.Find("player"); // playerのオブジェクトを取得する
    }

    void Update()
    {
        if (player.activeSelf == true)  // playerのステータスが「アクティブ」の場合
        {
            this.delta += Time.deltaTime;   // フレーム間の差をdelta変数に加算している
            if (this.delta > this.span) // delta変数がspanで指定した間隔を上回った場合
            {
                this.delta = 0; // 0に戻す処理
                GameObject cloneObject = Instantiate(enemyBullet, this.transform.position, Quaternion.identity);  // 弾を表示させて座標を移動させる処理
                cloneObject.name = "EnemyBullet";   // Cloneの名前を削除する処理
            }
        }
    }
}

6行目でplayerのオブジェクトを参照する変数を宣言して、Startメソッド内でFind関数を使いplayerのオブジェクトを代入しています。

このFind関数は、

GameObject.Find(引数);

と書くことで、引数に設定したオブジェクトを探してくる処理を行ってくれるので、これを使ってオブジェクトを代入しています。

プレイヤーに弾が当たった際は、SetActive関数で非表示にする処理を作っていたので、21行目でactiveSelfを使ってプレイヤーがアクティブかどうかをチェックしています。

activeSelfは、オブジェクトがアクティブかどうかを読み取るためのメソッドとなっていて、アクティブならtrue、非アクティブならfalse、とbool型で値を返してくれます。

これでプレイヤーがいなくなったら、敵が弾を発射しないという処理を作ることができました。

リトライの処理を加える

このままだと、プレイヤーが倒れたままゲームが続いてしまうので、プレイヤーが消去されてしまったらリトライするという処理を作っていきます。

リトライ処理は、あとで別のリトライシーンを作りもう少し処理を加えていくことになるので、ここでは一旦リトライされる処理だけを作っておきます。

リトライの処理を作るのは、「RetryDirector」というスクリプトを作ってその中で処理を行っていきます。

スクリプトを作成し、新しい空オブジェクトにアタッチしておきます。

using UnityEngine;
using UnityEngine.SceneManagement;  // LoadSceneメソッドを使うのに必要

public class RetryDirector : MonoBehaviour
{
    GameObject player;  // playerを参照する

    void Start()
    {
        player = GameObject.Find("player"); // playerのオブジェクトを取得する
    }

    void Update()
    {
        if (player.activeSelf == false)  // playerのステータスが「非アクティブ」の場合
        {
            SceneManager.LoadScene("MainScene");    // シーンを読み込んでリトライする
        }
    }
}

先ほどのプレイヤーのアクティブ状態で敵の発射するかしないかを決めたのと同じく、まず6行目と10行目でplayerのオブジェクトを取得しています。

15行目でactiveSelfを使ってplayerが非アクティブ状態の条件指定を作っています。

そして、17行目にリトライされるようにLoadSceneメソッドを使って同じシーンである「MainScene」を読み込む処理を行っています。

LoadSceneメソッドは、引数に指定したシーンを設定しておくことで、そのシーンを読み込むことが出来るメソッドです。

このLoadSceneメソッドは、SceneManagerが管理しているので、2行目でSceneManagerを使用する処理を書いておく必要があります。(バージョンによっては、自動で追加されます。)

実際にゲームを実行して、敵の攻撃を受けてみましょう。

敵の攻撃を受けたらプレイヤーが消去されて、再度始めからシーンが読み込まれて、リトライすることができました。

まとめ

このページでは、プレイヤーにダメージを与えて、リトライする処理を作っていきました。

プレイヤーのダメージ処理は、敵のダメージ処理と同じく、当たり判定を使って作ることができます。

そして、リトライを行う処理として、今回は「RetryDirector」というスクリプトの中でシーンを読み込む処理を行っています。

これである程度、シューティングゲームの根本が作れてきたので、次は敵を増やしてステージを作っていきます。

最後までお読みいただきまして、ありがとうございました!

コメント