<やりたいこと>
ParticleSystemのSub Emitter Deathに登録したパーティクルが発生時に効果音を出したい。
<やっていること>
unityでパーティクルを二つ用意し、片方をSub Emitters Deathでパーティクル消滅後に発生するような設定にしています。
消滅後に発生するパーティクルにAudio Sourceを割り当て、用意した効果音をAudioClipに設定しました。
Play on Awakeにチェックを入れ、パーティクル再生時に音を出すようにし、実行すると、実行後すぐに音が鳴り、またパーティクル発生時に音が鳴らない状態になりました。
<解決のためにやってみたこと>
Play on Awakeのチェックを外すと、実行後の音はなくなりましたが、パーティクル発生時の効果音はならない状態でした。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
検索したところ出てきたAccess to the particle system lifecycle events - Unity Forumでのやりとりを見ますに、どうやら自前で工夫しないといけないようですね。
私は未購入ですが、フォーラム中のMalvekaさんの投稿によると「Participle」なるものを作ったとのことで、導入を検討してみてもいいかもしれません。
また、Play sound on particle emit (sub emitter) - Unity Answersではパーティクル数の監視により生死のタイミングを判断するという案が出ていました。Laumaniaさんによる花火の作例(Fireworks - How To Play Sound Effect In Particle System - Unity Tutorial - YouTube)もご参考になりそうです。
原理的にどのパーティクルが生成または消滅したのか具体的な情報は得られず、また1フレーム内で生成と消滅が同時に起こった場合は正しく検出できない可能性が考えられますが、パーティクルの数を取得するだけですので動作上の負荷は小さそうです。
私からも一案として、サブエミッター機能を利用すればパーティクルが消えた時点の座標を得られるんじゃないかと思い、下記のようなスクリプトを作成してみました。
C#
1using System; 2using System.Linq; 3using UnityEngine; 4using UnityEngine.Events; 5 6// このスクリプトはメインのパーティクルシステムオブジェクトにアタッチすることを想定している 7[RequireComponent(typeof(ParticleSystem))] 8public class DeathDetector : MonoBehaviour 9{ 10 public OnDeathEvent onDeath; 11 12 private new ParticleSystem particleSystem; 13 private GameObject deathDetectorEmitter; 14 private ParticleSystem deathDetectorParticleSystem; 15 private ParticleSystem.Particle[] particles; 16 17 private void Awake() 18 { 19 if (this.onDeath == null) 20 { 21 this.onDeath = new OnDeathEvent(); 22 } 23 } 24 25 private void OnEnable() 26 { 27 // メインの子として、Burstでパーティクルを1発だけ発射するパーティクルシステムを作る 28 this.particleSystem = this.GetComponent<ParticleSystem>(); 29 this.deathDetectorEmitter = new GameObject("Death Detector Emitter"); 30 this.deathDetectorEmitter.transform.SetParent(this.transform, false); 31 this.deathDetectorParticleSystem = this.deathDetectorEmitter.AddComponent<ParticleSystem>(); 32 var shapeModule = this.deathDetectorParticleSystem.shape; 33 shapeModule.enabled = false; 34 var rendererModule = this.deathDetectorParticleSystem.GetComponent<ParticleSystemRenderer>(); 35 rendererModule.enabled = false; 36 var mainModule = this.deathDetectorParticleSystem.main; 37 mainModule.startSpeed = 0; 38 mainModule.simulationSpace = ParticleSystemSimulationSpace.World; 39 var emissionModule = this.deathDetectorParticleSystem.emission; 40 emissionModule.rateOverTime = 0; 41 emissionModule.SetBursts(new[] {new ParticleSystem.Burst(0, 1)}); 42 43 // それをメインのサブエミッター(Death)として登録する 44 var subEmittersModule = this.particleSystem.subEmitters; 45 subEmittersModule.AddSubEmitter( 46 this.deathDetectorParticleSystem, 47 ParticleSystemSubEmitterType.Death, 48 ParticleSystemSubEmitterProperties.InheritNothing); 49 50 // パーティクル取得用の配列を確保 51 this.particles = new ParticleSystem.Particle[mainModule.maxParticles]; 52 } 53 54 private void OnDisable() 55 { 56 // サブエミッターの登録を解除し、オブジェクトも破壊する 57 var subEmittersModule = this.particleSystem.subEmitters; 58 foreach (var i in Enumerable.Range(0, subEmittersModule.subEmittersCount) 59 .Select(i => (i, subEmittersModule.GetSubEmitterSystem(i))) 60 .Where(ps => ps.Item2 == this.deathDetectorParticleSystem).Select(ps => ps.Item1).Reverse()) 61 { 62 subEmittersModule.RemoveSubEmitter(i); 63 } 64 65 Destroy(this.deathDetectorEmitter); 66 this.particleSystem = null; 67 this.deathDetectorEmitter = null; 68 this.deathDetectorParticleSystem = null; 69 this.particles = null; 70 } 71 72 private void LateUpdate() 73 { 74 // 消滅検出用サブエミッターのパーティクル数を監視し... 75 if ((this.deathDetectorParticleSystem.particleCount > 0) && (this.onDeath != null)) 76 { 77 // パーティクルが出現していればデータを取得する 78 var count = this.deathDetectorParticleSystem.GetParticles(this.particles); 79 for (var i = 0; i < count; i++) 80 { 81 // 寿命を0にすることでパーティクルを削除させ... 82 this.particles[i].remainingLifetime = 0; 83 84 // パーティクルの座標を添えてイベントを発火させる 85 this.onDeath.Invoke(this.particles[i].position); 86 } 87 88 // データを書き戻す 89 this.deathDetectorParticleSystem.SetParticles(this.particles, count); 90 } 91 } 92 93 [Serializable] 94 public class OnDeathEvent : UnityEvent<Vector3> 95 { 96 } 97}
音を鳴らすのは別のスクリプトに担当させ...
C#
1using UnityEngine; 2 3public class AudioPlayer : MonoBehaviour 4{ 5 public AudioClip audioClip; 6 7 public void PlayAt(Vector3 position) 8 { 9 if (this.audioClip != null) 10 { 11 AudioSource.PlayClipAtPoint(this.audioClip, position); 12 } 13 } 14}
ヒエラルキー上に音声再生用のオブジェクトを用意しました。
イベントに呼応して再生メソッドを実行させるようにすると...
下図のようにパーティクルが消えた地点で音が鳴るようになりました。
投稿2020/10/08 21:29
編集2020/10/10 21:26総合スコア10811
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/10 15:41
2020/10/10 21:28
2020/10/11 02:35