###前提・実現したいこと
パーティクルシステムで作成された各パーティクルが、いずれかのオブジェクトと重なったときに、重なった先のオブジェクトを取得したいです。
私が想像していたのは「重なってもそのままオブジェクトを素通りした上で、重なったオブジェクトの情報を取得」することだったのですが、
Collisionモジュールを使ってしまうと衝突してしまい素通りできず、Trrigerモジュールを使った場合指定したオブジェクトとの重なりしか判定できずに困っております。
Collisionモジュールを使った場合
Collisionモジュールを使い、OnParticleCollisionでオブジェクトを取得しようとしたのですが、下記図のようにパーティクル(赤い丸)が対象(青い四角)に弾かれてしまいます。
確かに衝突は検知するのですが、以下の図のように重なる状態を維持したうえで、パーティクルと対象が重なったことを検知したいです。
Collides Withを使って対象を通り過ぎるようにしてしまうと、OnParticleCollision自体が発火しませんでした。
対象側でRaycastを使って見たのですが、パーティクルには反応してくれませんでした。
何かいい方法は無いでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
###[追記]各パーティクルの位置とオブジェクトの位置をUpdate内でチェックする
簡単で軽く良い方法が見当たらなかったのでCollision モジュールもTriggerモジュールも使用しない方法を考えてみました。やり方は単純ですべてのパーティクルの位置と該当のオブジェクトの位置を比較する方法です。
注意点
- Update内で毎回すべてのパーティクルの位置を取得して比較するので結構重そうです。
- オブジェクトとパーティクルが重なっている間中、連続して通知され続けます。
コードの参考 ※未検証です
オブジェクトは止まっていると仮定したコードです
パーティクルが画面外に出た場合の処理などは入れてません
1 パーティクルにアタッチするスクリプト
C#
1using System.Collections.Generic; 2using UnityEngine; 3using System; 4using System.Linq; 5 6[RequireComponent(typeof(ParticleSystem))] 7public class hitParticleWatcher : MonoBehaviour 8{ 9 ParticleSystem part; 10 List<monitoringObj> monitoringObjs = new List<monitoringObj>(); 11 12 public struct monitoringObj 13 { 14 public Vector3 pos; 15 public float distance; 16 public Action callBack; 17 } 18 19 void Start() 20 { 21 part = GetComponent<ParticleSystem>(); 22 } 23 24 /// <summary> 25 /// hitParticleWatcherに自身をセット 26 /// </summary> 27 /// <param name="pos">オブジェクトのポジション</param> 28 /// <param name="distance">どのぐらいの距離で重なったことにするかを指定</param> 29 /// <param name="callBack">重なった時に実行される関数</param> 30 public void monitoring(Vector3 pos, float distance, Action callBack) 31 { 32 var c = new monitoringObj(); 33 c.pos = pos; 34 c.distance = distance; 35 c.callBack = callBack; 36 monitoringObjs.Add(c); 37 } 38 39 void Update() 40 { 41 if(monitoringObjs.Count > 0 && part.particleCount > 0) 42 { 43 var ParticleList = new ParticleSystem.Particle[part.particleCount]; 44 part.GetParticles(ParticleList); 45 46 //パーティクルと重なったオブジェクトがあればコールバックを返す 47 monitoringObjs.Where( 48 x => ParticleList.Any( 49 p => Vector3.Distance( x.pos, p.position ) <= x.distance 50 ) 51 ).ToList().ForEach(x => { 52 x.callBack(); 53 hitObj( x ); 54 }); 55 } 56 } 57 58 //衝突したオブジェクトを取得 59 void hitObj(monitoringObj obj) 60 { 61 Debug.Log(obj.pos); 62 } 63}
2 オブジェクトにアタッチするスクリプト
C#
1using UnityEngine; 2 3public class obj : MonoBehaviour 4{ 5 //とりあえずインスペクターから設定するようにしました 6 [SerializeField] 7 hitParticleWatcher partWatcher; 8 9 void Awake() 10 { 11 //hitParticleWatcherに自身をセット 12 partWatcher.monitoring(gameObject.transform.position, 1f, hitParticle); 13 } 14 15 //重なっている間連続してメソッドが実行されるので注意してください。 16 void hitParticle() 17 { 18 Debug.Log("HIT"); 19 } 20}
###Collisionモジュールの衝突判定をなくす
※[追記] この方法ではOnParticleCollisionが走らないようです。
Collision モジュールをWorld モードで使用中でしたらCollides Withの値をEverythingから任意の値に変更することで衝突判定がなくなるようです。
Collides With パーティクルは選択されたレイヤーのオブジェクトとのみ衝突します(World モードのみで有効)。
https://docs.unity3d.com/jp/540/Manual/PartSysCollisionModule.html
###[追記] Collision モジュールでパーティクルが、オブジェクトと重なったときに、重なった先のオブジェクトを取得
Send Collision Messages の値を有効にすると、OnParticleCollision 関数を使用してスクリプトからパーティクルの衝突を検知することができます。
パーティクルシステムにOnParticleCollision 関数を実装したクラスをアタッチする
C#
1using UnityEngine; 2using System.Collections.Generic; 3 4public class ExampleClass : MonoBehaviour 5{ 6 public ParticleSystem part; 7 public List<ParticleCollisionEvent> collisionEvents; 8 9 void Start() 10 { 11 part = GetComponent<ParticleSystem>(); 12 collisionEvents = new List<ParticleCollisionEvent>(); 13 } 14 15 void OnParticleCollision(GameObject other) 16 { 17 int numCollisionEvents = part.GetCollisionEvents(other, collisionEvents); 18 19 int i = 0; 20 while (i < numCollisionEvents) 21 { 22 // 衝突したオブジェクトに何かしら処理をする 23 collisionEvents[i].colliderComponent.gameObject.SetActive(false); 24 i++; 25 } 26 } 27}
※コードは未検証です。オフィシャルのコードを元に改変しました。求めているものでない可能性もあります。一度試してみてください。
https://docs.unity3d.com/jp/540/ScriptReference/MonoBehaviour.OnParticleCollision.html
実装のポイントを上記リンクから引用
コライダー が現在のフレームで、あるパーティクルシステムの複数のパーティクルと衝突した場合でも、 コライダー は、指定されたフレームで衝突した各パーティクルシステムにつき、最多でも 1 つのメッセージしか受け取りません。 パーティクルシステム によるすべての衝突に関する詳細な情報を得たい場合は、 ParticlePhysicsExtensions.GetCollisionEvents を使って ParticleSystem.CollisionEvent の配列を取得する必要があります。
投稿2017/09/13 16:54
編集2017/09/16 05:24総合スコア1724
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/14 08:07
2017/09/14 08:31
2017/09/14 08:51
2017/09/14 10:07
2017/09/16 05:31