Unity学習記録 #013 衝突判定とタグを使った条件分岐

今回は衝突判定について基礎的な部分を勉強します。サンプルコードは前回のものを流用することにしました。
（前回の記事：<a href="https://qiita.com/sandddybridge/items/33de5e12fa85d2a22e6a">Unity学習記録 #012 プレイヤーの移動制御・ジャンプ制御</a>）

ゲーム開発が進むとプレイヤーが衝突するゲームオブジェクトも増えてきます。衝突する相手によって処理内容を分岐させたい場合、ゲームオブジェクトにタグを設定することで処理内容を分岐させることができるので、このあたりの実装を確認していきます。

【今回追加する条件】
・アイテムに触れるとアイテムオブジェクトが消滅
・敵に触れるとプレイヤーオブジェクトが消滅
・ゴールフラグ（触れるとbool型の変数をtrueに切り替え）

前回のコードに上記の条件を追加したサンプルコードを記述します。
```csharp
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Player : MonoBehaviour
{
    private Rigidbody2D rb;
    public float junpForce = 600.0f;
    public float speed = 5.0f;
    bool isGround;
    bool isGoal; //ゴールフラグ追加

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        isGoal = false; //ゲーム開始時のゴールフラグ設定
    }

    void Update()
    {
        Move();
        Jump();
    }

    void Move()
    {
        float xPos = Input.GetAxisRaw("Horizontal");
        transform.position += new Vector3(xPos, 0, 0) * Time.deltaTime * speed;
    }

    void Jump()
    {
        if (Input.GetKeyDown(KeyCode.Space) && isGround == true)
        {
            rb.AddForce(Vector2.up * junpForce);
            isGround = false;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Ground")) isGround = true;
    }

    //衝突判定と条件分岐
    private void OnTriggerEnter2D(Collider2D collision)
    {
        //コインオブジェクトの消滅
        if (collision.gameObject.CompareTag("Coin"))
        {
            Destroy(collision.gameObject);
        }

        //プレイヤーの消滅
        else if (collision.gameObject.CompareTag("Enemy"))
        {
            Destroy(gameObject);
        }

        //ゴールフラグの値の変更とテキスト表示
        else if (collision.gameObject.CompareTag("Goal"))
        {
            isGoal = true;
            Debug.Log("ゴール!");
        }
    }
}
```

## 解説
衝突判定の処理をするにはゲームオブジェクトのコンポーネントの設定とスクリプトが必要です。
まずはゲームオブジェクトに設定する内容を順に確認していきます。

### 衝突判定の設定（ゲームオブジェクト）
衝突判定はコライダー同士の接触がトリガーになりますので、ゲームオブジェクトに必要なコンポーネントを設定します。

・衝突判定に関係するゲームオブジェクトに「コライダー」を設定
　＞衝突判定の範囲を編集
　＞"Is Trigger" の有効・無効設定
・自身、もしくは衝突する相手のどちらかに「リジッドボディ」を設定（両方可）
・ゲームオブジェクトにタグの設定

コライダーはゲームオブジェクトに衝突判定の範囲（境界）を追加します。衝突判定に関わるゲームオブジェクト全てにコライダーが設定されます。衝突判定の範囲はプロパティの "Edit Collider" から編集可能です。また複数のコライダーを追加して組み合わせることで複雑な形状の衝突判定の範囲を設置することもできます。

![スクリーンショット 2024-07-10 135025 - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822122/7ab7de8b-cdc5-fd87-e604-e3b96ac2fd0a.png)

コライダーのプロパティ項目にある "Is trigger" は、衝突時の物理的な影響の有無を設定します。チェックを入れて有効にすると、コライダー同士が衝突しても物理的な影響を受けずにお互い何事もなかったかのように<b>すり抜ける</b>ような動きになります。ただし、コライダー同士が境界を越えた時の衝突判定はしっかり発生しています。

![IsTrigger.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822122/5f5e2408-5807-6290-fd78-e8d915c2315b.jpeg)

リジッドボディは衝突するオブジェクトのうち、最低どちらか一つに設定されていればいいですが、基本的には動き回るオブジェクト（ここではプレイヤー）に設定します。

衝突する相手によって処理内容を切り替えたい場合はゲームオブジェクトの「タグ」を利用して条件分岐させる方法があります。
ゲームオブジェクトを選択してインスペクターを確認するとタグの設定項目があります。使用したいタグがプルダウンリストにない場合はタグを新たに追加することも可能です。

![addTag.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822122/d42e110a-354f-fc5f-67ba-efa62273d267.jpeg)

プラスをクリックして新しいタグ名を追加します。

![addTag2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822122/c49c0bbe-9b39-1356-81fe-f53d93886b66.jpeg)

ゲームオブジェクトの最低限の設定項目は以上です。続いてスクリプトの内容を確認します。

### OnCollisionEnter2D
プレイヤーと地面の衝突判定には "OnCollisionEnter2D" を使いました。
```csharp
private void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.CompareTag("Ground")) isGround = true;
}
```
OnCollisionにはいくつか種類があるので参考に記載します。

| メソッド | 特徴 |
|---|---|
| OnCollisionEnter2D | コライダーが他のトリガーに接触した時に呼び出される |
| OnCollisionStay2D | 他のトリガーと接触している間、フレームの度に呼び出される |
| OnCollisionExit2D | 他のトリガーと接触が切れた時に呼び出される |

どのタイミングで処理を実行させるかによって上記のメソッドを使い分けます。

### OnTriggerEnter2D

OnTriggerも処理を実行するタイミングよって３種のメソッドが用意されています。

| メソッド | 特徴 |
|---|---|
| OnTriggerEnter2D | コライダーが他のトリガーに接触した時に呼び出される |
| OnTriggerStay2D | 他のトリガーと接触している間、フレームの度に呼び出される |
| OnTriggerExit2D | 他のトリガーと接触が切れた時に呼び出される |

"Is Torigger" が無効の場合：OnCollisionメソッドを使用
"Is Torigger" が有効の場合：OnTriggerメソッドを使用

両者のメソッドの使い分けはこれでいいと思います。

今回コードでは衝突時の物理的な影響は無視するために「コインオブジェクト」「敵オブジェクト」「ゴールオブジェクト」の"Is Trigger" は有効にしました。また、それぞれのゲームオブジェクトにタグを設定して条件分岐を使って実行する処理内容を分岐させています。
```csharp
//衝突判定と条件分岐
private void OnTriggerEnter2D(Collider2D collision)
{
    //コインオブジェクトの消滅
    if (collision.gameObject.CompareTag("Coin"))
    {
        Destroy(collision.gameObject);
    }

    //プレイヤーの消滅
    else if (collision.gameObject.CompareTag("Enemy"))
    {
        Destroy(gameObject);
    }
        
    //ゴールフラグの値の変更とテキスト表示
    else if (collision.gameObject.CompareTag("Goal"))
    {
        isGoal = true;
        Debug.Log("ゴール!");
    }
}
```
プレイヤーが衝突した際に、上記コードの変数 "collision" に衝突した相手のオブジェクトを取得します。そして条件分岐で変数 "collision" のタグ名を判定して、タグごとに処理したい内容を記述します。

衝突した相手のタグが"Coin"だった場合、コインを消滅させるために、 "Destroy" メソッドを使ってゲームオブジェクトを消滅させています。

同様に"Destroy" メソッドを使って、敵に衝突した場合には自身のオブジェクトを消滅させています。

ゴールに触れると、bool型の変数の中身をtrueに切り替えています。このフラグを使ってゲームクリアの処理を実行させたり、別の処理に利用したりできます。