【Unity】オブジェクトの衝突位置にエフェクトを表示させる方法

衝突した位置にエフェクトを表示する Unity

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

このページでは、

「衝突した場所にエフェクトを表示させたい!」

「衝突した位置はどうやって取得するの?

というお悩みの方に向けた内容となっています。

Unityでオブジェクトの衝突地点にエフェクトを表示させる場合、オブジェクト同士がすり抜けないOnCollision関数で行うか、すり抜けるOnTrigger関数で行うかで実装方法が変わってきます。

OnCollision関数で衝突判定を行う場合は、CollisionクラスのContactPointという接触点の情報を使って、衝突地点の座標を正確に取得できるので、その座標にエフェクトを表示させます。

一方で、OnTrigger関数で当たり判定を行う場合は、正確な座標では無いですが、ColliderクラスのClosestPointを使って、相手の座標からコライダー上の最も近い点を取得して、その場所にエフェクトを表示させることで、同じような処理を作ることができます。

そこで、このページでは、Unityでオブジェクトが衝突した位置にエフェクトを表示させる方法として、OnCollision関数とOnTrigger関数のそれぞれのパターンでまとめていきます。

この記事を書いた人

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

OnCollision関数で衝突した位置にエフェクトを表示させる場合

まずは、OnCollision関数でオブジェクト同士の衝突判定を行った場合に、衝突地点にエフェクトを表示させる方法を紹介していきます。

ここでは、以下のように2Dゲーム上で円形のオブジェクトを落下させて、床のオブジェクトと衝突した地点にエフェクトを表示させるという処理を作っていきます。

ちなみに、床のオブジェクトにはBoxCollider2D、円形のオブジェクトにはCircleCollider2DRigidbody2Dが紐づいています。

OnCollision関数で衝突判定を行う

まずは、OnCollision関数を使って衝突判定が行われるようにしていきます。

床のオブジェクトに対して、以下のスクリプトをアタッチします。

using UnityEngine;

public class Test : MonoBehaviour
{
    void OnCollisionEnter2D(Collision2D collision)
    {
        Debug.Log("衝突!");
    }
}

5行目でOnCollisionEnter2Dメソッドを使って衝突判定を行い、その中で「衝突!」と判定されているのが分かるように記述しています。

問題なく衝突判定が行われていますね。

もし、上手く判定がされていない場合は、以下の記事にOnCollision関数の使い方についてまとめていますので、参考にしてみてください。

GetContactメソッドでContactPointを取得する

次に、オブジェクト同士が衝突した際の情報を取得するために、GetContactメソッドContactPointという構造体を取得していきます。

ContactPointとは、オブジェクト同士が衝突した際の接触点の情報を管理している構造体で、この構造体を使って衝突地点の座標を取得することができます。

そして、このContactPointは、Collisionクラスで管理されている構造体で、以下のGetContactというメソッドを使うことで取得することができます。

Collision.GetContact(index);

index:接触情報を取得したいインデックス(int型)

GetContactの引数は、接触点となる場所が複数あるような場合、どの接触点の情報を取得するか整数(int型)で指定するものになっています。

今回のように接触点が一つしか無いような場合は、引数に「0」を指定してあげれば問題ありません。

それでは、先ほどの床のオブジェクトに紐づけたスクリプトの中で、ContactPointを取得するように記述してみます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void OnCollisionEnter2D(Collision2D collision)
    {
        ContactPoint2D contact = collision.GetContact(0);
    }
}

今回は2Dゲームなので、7行目でContactPoint2D型の変数を作成しています。

その右辺の部分で、衝突した際に取得できるCollision型の変数からGetContactメソッドを使って、ContactPointを取得してあげます。

これで、接触点の情報を取得することができました。

衝突位置にエフェクトを移動させて表示する

あとは、取得したContactPointの中のpoint変数に、接触点の座標がVector3型で管理されているので、その値を使ってエフェクトを移動させて表示させます。

ここでは、エフェクトとして以下の爆発するアニメーションのオブジェクトをPrefab化して使っていきます。

ぴぽや倉庫様より、ダウンロードした素材を使用させて頂いております。

先ほどのスクリプトに、エフェクトを表示させる処理を追加していきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject effect;   // エフェクトを入れる変数を宣言

    void OnCollisionEnter2D(Collision2D collision)
    {
        ContactPoint2D contact = collision.GetContact(0);
        GameObject cloneEffect = Instantiate(effect);       // エフェクトを生成させる処理
        cloneEffect.transform.position = contact.point;     // エフェクトの表示位置を衝突位置に変更する処理
    }
}

5行目でエフェクト用にGameObject型の変数をpublicで宣言しておき、インスペクターウィンドウからPrefabファイルを代入しておきます。

オブジェクトが衝突した際に、10行目でInstantiateメソッドを使ってエフェクトを生成する処理を行っています。

そして、11行目で生成されたオブジェクトの座標を、衝突地点となるContactPointのpoint変数の値に置き換えています。

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

上記のように、オブジェクトが衝突した位置にエフェクトを表示できているのが分かります。

OnTrigger関数で当たった位置にエフェクトを表示させる場合

次に、OnTrigger関数でオブジェクトの当たり判定を行った場合に、その当たった地点にエフェクトを表示させる方法を紹介していきます。

ここでは、以下のように2Dゲーム上で円形のオブジェクトを横に移動させて、四角のオブジェクトと当たった地点にエフェクトを表示させるという処理を作っていきます。

なお、円形のオブジェクトにはCircleCollider2DRigidbody2D、四角のオブジェクトにはBoxCollider2Dが紐づいていて、Rigidbody2DのBodyTypeを「Kinematic」、コライダーの「isTrigger」にチェックを入れてすり抜けるようにしています。

冒頭でも解説した通り、OnTrigger関数の場合は正確な当たり判定の地点は取得できないため、できるだけ近い地点を取得して行う方法となります。

OnTrigger関数で当たり判定を行う

まずは、OnTrigger関数で当たり判定が行われるようにしていきます。

円形のオブジェクトに対して、以下のスクリプトをアタッチしていきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Update()
    {
        transform.Translate(0.01f, 0, 0);   // オブジェクトの移動処理
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        Debug.Log("当たり!");
    }
}

10行目でOnTriggerEnter2Dメソッドを使って当たり判定を行い、12行目で判定が行われているのが分かるように「当たり!」と表示されるように記述しています。

オブジェクト同士はすり抜けますが、問題なく当たり判定が行われています。

もし、上手く判定がされていない場合は、以下の記事にOnTrigger関数の使い方についてまとめていますので、参考にしてみてください。

ClosestPointで相手のコライダー内の最も近い地点を取得する

OnTrigger関数では、Collisionクラスを取得できないため、ContactPointの構造体を使うことができません。

そこで、ColliderクラスにあるClosestPointというメソッドを使って、当たり判定が行われたとされる地点を決めていきます。

ClosestPointというメソッドは、以下のように記述することで、引数で指定した座標に最も近いコライダー内の地点Vector3型で取得することができます。

Collider.ClosestPoint(position);

position:指定したい地点(Vector3型)

そして、このClosestPointの引数に相手の座標を指定してあげることで、相手との最短距離にあるコライダーの地点を取得することができます。

そのため、当たり判定が行われた際にClosestPointを使うことで、実際にコライダー内で当たった地点と非常に近い場所が取得できることになります。

ちなみに、引数に指定した座標がコライダーの中にある場合は、その座標がそのまま返ってくるようになっています。

ただし、正確な座標では無く、条件次第で大きくずれる可能性もあるため、注意しておきましょう。

先ほどの円形のオブジェクトに紐づけたスクリプトの中で、ClosestPointを記述してみます。

using UnityEngine;

public class Test : MonoBehaviour
{
    void Update()
    {
        transform.Translate(0.01f, 0, 0);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        Vector3 hitPos = collider.ClosestPoint(transform.position);     // 当たり判定に近い座標を取得する
    }
}

12行目で相手のCollider情報を使って、ClosestPointの引数に自身の座標位置を指定してあげることで、その座標から最も近い相手のコライダーの地点を取得するようにしています。

エフェクトを取得した位置に移動して表示する

あとは、OnCollision関数の時と同様に、エフェクトを生成した際の座標位置を先ほどの値に置き換えてあげます。

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject effect;   // エフェクトを入れる変数を宣言

    void Update()
    {
        transform.Translate(0.01f, 0, 0);
    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        Vector3 hitPos = collider.ClosestPoint(transform.position);
        GameObject cloneEffect = Instantiate(effect);   // エフェクトを生成する処理
        cloneEffect.transform.position = hitPos;        // エフェクトの位置を変更する処理
    }
}

16行目で生成されたエフェクトの座標位置をClosestPointで取得した座標に変更しています。

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

オブジェクトの当たり判定が行われた場所にエフェクトが表示されるようになりました。

まとめ

このページでは、Unityでオブジェクトが衝突した位置にエフェクトを表示させる方法について、OnCollision関数とOnTrigger関数を使った場合で分けて紹介していきましたが、いかがでしたでしょうか?

OnCollision関数を使って衝突判定を行う場合は、CollisionクラスのGetContactメソッドでContactPointの構造体を取得することで、衝突位置にエフェクトを表示させることができるようになります。

一方で、OnTrigger関数で当たり判定を行う場合は、ColliderクラスのClosestPointメソッドで相手の座標を指定してあげることで、コライダー内の最も近い地点を取得して、エフェクト表示することができます。

ただし、ContactPointと違って、ClosestPointは正確な当たり判定の地点では無いため、移動速度が速い場合などでずれる可能性があるため注意しておきましょう。

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

コメント