今回はUnityネタをやっていきます。
Particle Systemで作ったエフェクトに合わせて回りのオブジェクトを吹き飛ばしてみます。
キーワードはRigidbody.AddExplosionForceです。
開発環境
Unity 2020.3.12f1
Rigidbody.AddExplosionForceとは
爆発をシミュレートする力をRigidbodyに与えるメソッドです。
public void AddExplosionForce(float explosionForce, Vector3 explosionPosition, float explosionRadius, float upwardsModifier = 0.0f, ForceMode mode = ForceMode.Force));
パラメータ
explosionForce
爆発力、大きければ大きいほど吹き飛ばす力が大きくなります。
距離によって減衰します。
explosionPosition
力を発生させる原点です。
explosionRadius
力が影響を与える範囲です。半径で表します。
upwardsModifier
爆発時、上方向に加える力です。
デフォルト値は0ですが、値を大きくすると上方向に追加で力を加えることができます。
舞い上がらせたい時に使うとよさそう。
mode
力の加え方です。
いくつか種類がありますが、一瞬だけ大きな力を加える場合はImpulseが良いです。
詳しくはこちら
実際に試してみる
周辺にCubeを置く
適当にCubeを配置します。
CubeにはBox ColliderとRigidbodyをアタッチしておきます。
ちなみにRigidbodyのMassの値で吹き飛ばされやすさを調整できます。
爆発用Particle Systemを置く
視覚的にわかりやすいよう爆発エフェクトを置いておきます。
これはなんでもいいです。
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に先ほど配置した爆発エフェクトを紐づける
完成
これで完成です。
キーボードのエンターキーを押すとParticle Systemが再生され、爆心地から半径5mのCubeを吹き飛ばします。
間に遮蔽物があったら吹き飛ばないようにする
応用編。
このままでは間に壁があっても貫通して吹き飛ばされてしまいます。
これを解決します。
遮蔽物を作成
Cubeの作成
遮蔽物となる壁を作成します。Cubeを変形させて作りました。
Layerの設定
遮蔽物かどうかを判定するため専用のLayerを用意します。
(LayerではなくTagや判定用のScriptでやってもいい)
今回はLayer18にWallを設定します。
Inspectorの設定
LayerをWallにし、RigidbodyのisKinematicを有効にします。
これが有効だと物理演算の影響を受けなくなります。
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のレイヤー番号を入力します。
完成
これで完成です。
間に遮蔽物があると爆発の影響を受けなくなりました。
まとめ
・Rigidbody.AddExplosionForceを使えば、爆発をシミュレートしオブジェクトを吹き飛ばすことができる
・Rayを飛ばして遮蔽物があるかどうか判定することで、吹き飛ばないようにできる
以上です。
参考資料