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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

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

Q&A

解決済

1回答

6009閲覧

unityでパーティクルのSub Emitterを利用した効果音の再生方法

rekutasu

総合スコア13

Unity

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

0グッド

0クリップ

投稿2020/10/05 13:51

<やりたいこと>

 ParticleSystemのSub Emitter Deathに登録したパーティクルが発生時に効果音を出したい。

<やっていること>

 unityでパーティクルを二つ用意し、片方をSub Emitters Deathでパーティクル消滅後に発生するような設定にしています。

消滅後に発生するパーティクルにAudio Sourceを割り当て、用意した効果音をAudioClipに設定しました。

 Play on Awakeにチェックを入れ、パーティクル再生時に音を出すようにし、実行すると、実行後すぐに音が鳴り、またパーティクル発生時に音が鳴らない状態になりました。

<解決のためにやってみたこと>

 Play on Awakeのチェックを外すと、実行後の音はなくなりましたが、パーティクル発生時の効果音はならない状態でした。

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

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

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

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

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

guest

回答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}

ヒエラルキー上に音声再生用のオブジェクトを用意しました。

図1-1

イベントに呼応して再生メソッドを実行させるようにすると...

図1-2

下図のようにパーティクルが消えた地点で音が鳴るようになりました。

図2

投稿2020/10/08 21:29

編集2020/10/10 21:26
Bongo

総合スコア10811

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

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

rekutasu

2020/10/10 15:41

丁寧に調べていただきありがとうございました。 現在、いただいたコードを少しづつ理解していこうと頑張っています。 困った点があり、いただいたコードを実行しようとしたのですが、Death Detector(Script)のOn DeathにAudioPlayerをアタッチしましたが、AudioPlay.PlayAtが表示されずNo Function表記になってしまいます。ヒエラルキー上では、GameObjectにAudioPlay(script)を割り当て、AudioClipに流したい効果音を割り当てています。 作成しているのは花火で、花火の打ちあがるパーティクルと打ちあがった後の広がるパーティクルの二つを作成しています。いただいたDeathDetector(script)はどちらにアタッチすべきでしょうか。またDeathDetector(script)は打ちあがるパーティクルはスクリプト内で作成しているのですか? 長くなってしまい、申し訳ありません。 もし時間がありましたら、教えていただけると幸いです。
Bongo

2020/10/10 21:28

もしかして「On Death (Vector3)」イベントのターゲット欄に、プロジェクトビュー内にあるAudioPlayerスクリプトファイルそのものをセットしてしまってはいませんでしょうか? 何らかのオブジェクトにAudioPlayerをアタッチして、さらにそれを「On Death (Vector3)」イベントのターゲット欄にセットすればプルダウンメニューにメソッド候補が出てくるかと思います。さしあたり私の場合はヒエラルキー上に空のオブジェクトを作って「AudioPlayer」と名前を付け、それにAudioPlayerをアタッチして使いました。 回答中の図をもう少し詳しいものに差し替えてみました。 DeathDetectorをアタッチするのはメインのパーティクルシステム...つまり打ち上がる側ですね。また、確かにDeathDetectorスクリプトはサブエミッターを独自に作成する作りになっていますが、このサブエミッターが発射するのは消滅タイミング検出目的の目に見えないパーティクルですので、爆発して星が飛び散る演出を表現するサブエミッターは別途登録する必要があるでしょう。
rekutasu

2020/10/11 02:35

Bongoさんのいう通りスクリプトファイルをそのままセットしていました。 オブジェクトにアタッチし、セットするとうまく動きました。 またunityでやりたかったパーティクルの動きができるようになりました。 もっと自分で考えてコードを書いたり、イメージできるように頑張ります。 最後まで付き合っていただき本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問