【Unity】パーティクルでハマったこと(発生が遅い、移動してくれない、再生速度の変更)

2023年2月28日

概要

個人プロジェクトのプロトタイピングで、久々に Unity の ParticleSystem を扱ったところみごとにハマってしまいました…。

タイトルの通り以下の問題にぶち当たりました。

  • エフェクトを移動させても何故か追従してくれない。
  • エフェクトの発生が遅くレスポンスが悪く見える。
  • 再生速度の変更方法がわからない。

使用したUnity バージョン:2020.2.2f1

以下の通り、プレイヤーから弾を発射してから約1秒後にエフェクトが表示されて、しかもその場に置いてけぼりにされます…。

使用アセット

今回はプレイヤーのスプライトをお借りしてます。
Simple 2D Template

今回はエフェクトをお借りしてます。
3D Games Effects Pack Free

エフェクトが移動しない

今回はエフェクトのオブジェクトを弾オブジェクトの子供として追加してみました。
オブジェクト自体は子なのでちゃんと親に追従するはずと思ったのですが…。

これはちょっと過去に経験していたはずなのに忘れていたのですが、
Inspector で Simulation Space を Local にすると解決します。

無事追従する様になりました。

エフェクトの発生が遅い

これがなかなか解決できずに時間を要しました…。
ParticleSystem を Inspector で確認し、エフェクトの発生頻度を設定する Emission モジュールを確認します。
Rate over Time が秒間の発生回数っぽいので増やしてみたのですがダメでした。

その後、ネットをさまよいこちらの記事を見つけました。(アリガトウゴザイマス)
【ParticleSystem】RateOverTimeの罠

この記事によると Rate over Time を増やしたからと言って発生タイミングが早くなるとは限らない様です。

これについて有効なのは Bursts に設定を追加すること。
今回は弾のエフェクトなので一応 Count は 1 にしました。

無事、エフェクトがすぐ表示される様になりました。

再生速度の変更方法がわからない

別のエフェクトで再生速度を調整したいと思うことがありました。
再生速度は Inspector 上では、Simulation Speed を変更すれば良いようです。

ただ発生条件などにより動的に再生速度を変更したい場合はスクリプトを使う方が効率が良いでしょう。
しかしスクリプトからの変更方法が変わった様で戸惑いました。

動的なパーティクルのパラメータ変更を行うには、ParticleSystemコンポーネントを取得します。
昔は playbackSpeed プロパティで変更できたのですが非推奨の様です。

ParticleSystem particleSystem = effectObj.GetComponentInChildren<ParticleSystem>();
if (particleSystem)
{
    particleSystem.playbackSpeed = 10;
}

どうやら現在は、モジュール(機能の分類)毎に構造体に分割されているようです。
再生速度のプロパティは MainModule に含まれています。
Inspector と同じ名前の simulationSpeed というプロパティがありました。

ParticleSystem particleSystem = effectObj.GetComponentInChildren<ParticleSystem>();
if (particleSystem)
{
    ParticleSystem.MainModule mainModule = particleSystem.main;
    mainModule.simulationSpeed = 10;
}

注意点として mainプロパティを直接変更することはできません。

ParticleSystem particleSystem = effectObj.GetComponentInChildren<ParticleSystem>();
if (particleSystem)
{
    particleSystem.main.simulationSpeed = 10;
}

エラーメッセージは以下のようになっていました。

error CS1612: Cannot modify the return value of 'ParticleSystem.main' because it is not a variable

エラーコードの CS1612 について調べると、プロパティから取得した値型(構造体)を直接変更してはならないとのこと。
これは、transform.position を直接変更しようとしても起きる問題ですね。

これ、昔はエラーを吐いてくれなくて問題に気付かないことがあったと思うのですが、今はちゃんとエラーにしてくれるんですね♪

おわりに

最近はUnityにあまり触っていなかったので、色々と挙動が理解できずにハマってしまいました。
こういう時の為にも自分用のメモという意味も込めて記事を書いていけたらと思います。