Raspberlyのブログ

Raspberlyのブログ

Unityネタをメインとした技術系ブログです。にゃんこ大戦争や日常なども。そろそろブログタイトル決めたい

【Unityネタ】爆発でオブジェクトを吹き飛ばす【AddExplosionForce】

今回はUnityネタをやっていきます。
Particle Systemで作ったエフェクトに合わせて回りのオブジェクトを吹き飛ばしてみます。
キーワードはRigidbody.AddExplosionForceです。

f:id:Raspberly:20210625011740g:plain

 

f:id:Raspberly:20210625030724p:plain

 

 

開発環境

Unity 2020.3.12f1

 

 

 

Rigidbody.AddExplosionForceとは

爆発をシミュレートする力をRigidbodyに与えるメソッドです。

docs.unity3d.com

public void AddExplosionForce(float explosionForceVector3 explosionPosition, float explosionRadius, float upwardsModifier = 0.0f, ForceMode mode = ForceMode.Force));

パラメータ

explosionForce

爆発力、大きければ大きいほど吹き飛ばす力が大きくなります。
距離によって減衰します。

explosionPosition

力を発生させる原点です。

explosionRadius

力が影響を与える範囲です。半径で表します。

upwardsModifier

爆発時、上方向に加える力です。
デフォルト値は0ですが、値を大きくすると上方向に追加で力を加えることができます。
舞い上がらせたい時に使うとよさそう。

f:id:Raspberly:20210625020215g:plain

mode

力の加え方です。
いくつか種類がありますが、一瞬だけ大きな力を加える場合はImpulseが良いです。
詳しくはこちら

ekulabo.com

 

 

 

実際に試してみる

周辺にCubeを置く

適当にCubeを配置します。

f:id:Raspberly:20210625003413p:plain
CubeにはBox ColliderとRigidbodyをアタッチしておきます。

f:id:Raspberly:20210625003445p:plain

ちなみにRigidbodyのMassの値で吹き飛ばされやすさを調整できます。

 

爆発用Particle Systemを置く

視覚的にわかりやすいよう爆発エフェクトを置いておきます。
これはなんでもいいです。

f:id:Raspberly:20210625004509g:plain

 

 

ExplosionSample1コンポーネントをアタッチ

空のGameObjectを作成し、以下のExplosionSample1をアタッチする。

using UnityEngine;

public class ExplosionSample1 : MonoBehaviour
{
    [SerializeField] ParticleSystem m_particle;
    [SerializeField] float m_force = 20;
    [SerializeField] float m_radius = 5;
    [SerializeField] float m_upwards = 0;
    Vector3 m_position;

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Return))
        {
            Explosion();
        }
    }

    public void Explosion ()
    {
        m_particle.Play();
        m_position = m_particle.transform.position;

        // 範囲内のRigidbodyにAddExplosionForce
        Collider[] hitColliders = Physics.OverlapSphere(m_position, m_radius);
        for(int i = 0; i < hitColliders.Length; i++)
        {
            var rb = hitColliders[i].GetComponent<Rigidbody>();
            if(rb)
            {
                rb.AddExplosionForce(m_force, m_position, m_radius, m_upwards, ForceMode.Impulse);
            }
        }
    }
}

Particleに先ほど配置した爆発エフェクトを紐づける

f:id:Raspberly:20210625013306p:plain

 

 

完成

これで完成です。
キーボードのエンターキーを押すとParticle Systemが再生され、爆心地から半径5mのCubeを吹き飛ばします。

f:id:Raspberly:20210625011740g:plain



 

 

間に遮蔽物があったら吹き飛ばないようにする

応用編。
このままでは間に壁があっても貫通して吹き飛ばされてしまいます。

f:id:Raspberly:20210625013213g:plain

これを解決します。

 

遮蔽物を作成

Cubeの作成

遮蔽物となる壁を作成します。Cubeを変形させて作りました。

f:id:Raspberly:20210625013825p:plain

Layerの設定

遮蔽物かどうかを判定するため専用のLayerを用意します。
(LayerではなくTagや判定用のScriptでやってもいい)

 

今回はLayer18にWallを設定します。

f:id:Raspberly:20210625014159p:plain


Inspectorの設定

LayerをWallにし、RigidbodyのisKinematicを有効にします。
これが有効だと物理演算の影響を受けなくなります。

f:id:Raspberly:20210625014642p:plain

 

ExplosionSample2コンポーネントをアタッチ

空のGameObjectを作成し、以下のExplosionSample2をアタッチする。

using UnityEngine;

public class ExplosionSample2 : MonoBehaviour
{
    [SerializeField] ParticleSystem m_particle;
    [SerializeField] float m_force = 20;
    [SerializeField] float m_radius = 5;
    [SerializeField] float m_upwards = 0;
    [SerializeField] int m_wallLayer = 0;
    Vector3 m_position;

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Return))
        {
            Explosion();
        }
    }

    public void Explosion ()
    {
        m_particle.Play();
        m_position = m_particle.transform.position;

        Collider[] hitColliders = Physics.OverlapSphere(m_position, m_radius);
        for(int i = 0; i < hitColliders.Length; i++)
        {
            var rb = hitColliders[i].GetComponent<Rigidbody>();
            if(rb)
            {
                // Rayを飛ばして壁を挟んでいたら無視する
                var hits = Physics.RaycastAll(m_position, hitColliders[i].transform.position - m_position, m_radius);
                bool block = false;
                foreach(var o in hits)
                {
                    if(o.collider.gameObject.layer == m_wallLayer)
                    {
                        block = true;
                        break;
                    }
                }
                if(!block)
                {
                    rb.AddExplosionForce(m_force, m_position, m_radius, m_upwards, ForceMode.Impulse);
                }
            }
        }
    }
}

AddExplosionForceする前にRayを飛ばして遮蔽物があるかどうか判定する処理を入れています。

 

Inspectorの設定はこんな感じ、
Wall Layerには、先ほど作成したWallのレイヤー番号を入力します。

f:id:Raspberly:20210625015636p:plain

 

 

 

完成

これで完成です。
間に遮蔽物があると爆発の影響を受けなくなりました。

f:id:Raspberly:20210625015549g:plain

 

 

 

まとめ

Rigidbody.AddExplosionForceを使えば、爆発をシミュレートしオブジェクトを吹き飛ばすことができる

・Rayを飛ばして遮蔽物があるかどうか判定することで、吹き飛ばないようにできる

 

 

以上です。

 

 

 

参考資料

docs.unity3d.com

 

docs.unity3d.com

sleepygamersmemo.blogspot.com

 

docs.unity3d.com

docs.unity3d.com

 

unity-shoshinsha.biz

 

nopitech.com