質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1054閲覧

Unity2Dでパーティクルと重なったオブジェクトを取得したい

koronatail

総合スコア433

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2017/09/13 10:47

編集2017/09/14 10:06

###前提・実現したいこと
パーティクルシステムで作成された各パーティクルが、いずれかのオブジェクトと重なったときに、重なった先のオブジェクトを取得したいです。

私が想像していたのは「重なってもそのままオブジェクトを素通りした上で、重なったオブジェクトの情報を取得」することだったのですが、
Collisionモジュールを使ってしまうと衝突してしまい素通りできず、Trrigerモジュールを使った場合指定したオブジェクトとの重なりしか判定できずに困っております。

Collisionモジュールを使った場合
Collisionモジュールを使い、OnParticleCollisionでオブジェクトを取得しようとしたのですが、下記図のようにパーティクル(赤い丸)が対象(青い四角)に弾かれてしまいます。
イメージ説明

確かに衝突は検知するのですが、以下の図のように重なる状態を維持したうえで、パーティクルと対象が重なったことを検知したいです。
イメージ説明
Collides Withを使って対象を通り過ぎるようにしてしまうと、OnParticleCollision自体が発火しませんでした。
対象側でRaycastを使って見たのですが、パーティクルには反応してくれませんでした。

何かいい方法は無いでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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から任意の値に変更することで衝突判定がなくなるようです。

Collision モジュール

Collides With パーティクルは選択されたレイヤーのオブジェクトとのみ衝突します(World モードのみで有効)。

https://docs.unity3d.com/jp/540/Manual/PartSysCollisionModule.html

###[追記] Collision モジュールでパーティクルが、オブジェクトと重なったときに、重なった先のオブジェクトを取得

Send Collision Messages の値を有効にすると、OnParticleCollision 関数を使用してスクリプトからパーティクルの衝突を検知することができます。

Send Collision Messagesをオンにする
Collision モジュール

パーティクルシステムに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
IShix

総合スコア1724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koronatail

2017/09/14 08:07

IShikawan様 回答ありがとうございます。Collides Withとぶつかるようにはなったのですが、重なったかどうかを判定したかったです・・・言葉足らずで申し訳ありません。RayCastを個々のパーティクルで判定するようなことができればと考えています。
IShix

2017/09/14 08:31

Collisionモジュールで重なったGameObjectを参照できそうですがこれでできませんか?追記しましたので見てみてください。質問内容を理解できていなければすみません。
IShix

2017/09/14 08:51

コードにミスがありましたので修正しました。検証はしていないので一度試してみていただきたいです。
koronatail

2017/09/14 10:07

IShikawan様 度々ありがとうございます・・・。Collides Withを使って判定したいオブジェクトを衝突対象から外すと、確かに重なりはするのですがOnParticleCollision自体が呼び出されませんでした。状況を質問に追記させていただきました。
IShix

2017/09/16 05:31

そうでしたか、失礼しました。調べてみたのですが良い方法が見当たらずモジュールを使用しない方法を考えてみましたのでごらんください。 あとは、パーティクルを使わずオブジェクトで表現していく方法を検討されても良いかと思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問