【Unity】パーティクルシステムの再生が終了した際の処理を実装する方法

パーティクルの再生終了を判定 Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「パーティクルシステムの再生終了を判定したい!」

「パーティクルシステムが終わったら処理を行いたい!」

というお悩みの方に向けた内容となっています。

Unityでは、パーティクルシステムを使ってゲーム内でのエフェクトを作成することができます。

このパーティクルシステムの再生が終了したタイミングで、何かしらの処理を実行したい場合は、コンポーネント内の「StopAction」の設定で実装することができます。

このStopActionの設定では、そのパーティクルシステムのオブジェクトを無効化したり削除したりするだけでなく、コールバックを実装してスクリプトで記述した処理を実行することができます。

そこで、このページでは、Unityでパーティクルシステムを使う場合に、再生が終了した際の処理を実装する方法をまとめていきます。

開発環境
  • Windows11
  • Unity 6.3 LTS(6000.3.2f1)
この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

パーティクルシステムの再生が終了した際の処理を作る方法

それでは早速、パーティクルシステムの再生が終了した際の処理を作る方法を紹介していきます。

「StopAction」で再生が終わった場合の処理を選択できる

パーティクルシステムの再生が終了した場合の処理は、コンポーネント内にある「StopAction」という項目で設定することができます。

このStopActionは、新しいパーティクルの放出が行われず、それまでに放出したパーティクルが全て消滅した場合、つまりパーティクルシステムの再生が終わった場合に、どのような処理を行うかを設定できる項目です。

なお、ループ処理の設定がされていると、StopActionが実行されないため、「Looping」のチェック項目も外しておく必要があります。

StopActionの設定項目では、

  • None:何も処理を行わない
  • Disable:オブジェクトを無効にする
  • Destroy:オブジェクトを削除する
  • Callback:コールバックの処理を実行する

上記の4つから選択することができます。

実際に、ここでは以下のような2秒間表示される簡単なパーティクルシステムを作って、それぞれのStopActionの設定を確認してみます。

None:何も処理を行わない

Noneは、パーティクルシステムの再生が終了しても、何も処理を実行しません。

実際に、StopActionを「None」にしてパーティクルシステムを再生してみますが、

再生が終了しても何も行われず、パーティクルシステムのオブジェクト自体も残ったままとなります。

Disable:オブジェクトを無効にする

Disableは、パーティクルシステムの再生が終了すると、オブジェクトを無効化(非アクティブ化)します。

実際に、StopActionを「Disable」にして、パーティクルシステムを再生してみると、

再生の終了後に、パーティクルシステムのオブジェクトが無効化されているのが分かります。

このDisableの設定は、そのパーティクルシステムをもう一度アクティブ化して再生するような場合に最適です。

Destroy:オブジェクトを削除する

Destroyは、パーティクルシステムの再生が終了すると、そのオブジェクトを削除(破壊)する処理を実行します。

StopActionを「Destroy」にしてパーティクルシステムを再生してみると、

再生が終了したタイミングで、パーティクルシステムのオブジェクトが削除されているのが分かります。

このDestroyの設定は、そのパーティクルシステムは一度きりでその後は使わないという場合に最適です。

Callback:コールバックで処理を実行する

Callbackは、パーティクルシステムの再生が終了すると、そのパーティクルシステムに紐づけたスクリプト内の「OnParticleSystemStopped」というメソッドを実行します。

実際に、以下のようなスクリプトを作成してパーティクルシステムのオブジェクトに紐づけておきます。

using UnityEngine;

public class TestParticleStop : MonoBehaviour
{
    void OnParticleSystemStopped()
    {
        Debug.Log("再生終了");
    }
}

5行目でOnParticleSystemStoppedメソッドを定義していて、その中でコンソールウィンドウにテキストを表示する処理を記述しています。

これで、StopActionを「Callback」にしてパーティクルシステムを再生してみると、

再生の終了後に、コンソールウィンドウにテキストが表示されるようになりました。

このCallbackの設定は、パーティクルシステムが再生終了した際の処理をスクリプトで記述できるので、これまでの無効化や削除以外の処理を作りたい場合に使います。

再生が終了したらオブジェクトプールに返却する処理

パーティクルシステムで作成したエフェクトをオブジェクトプールで管理しているような場合に、StopActionの設定を使うと、再生が終了したタイミングでプールに返却する処理を行うことができます。

そもそもオブジェクトプールとは、大量のオブジェクトを何度も使うような場合に、使い終わったオブジェクトを非アクティブ化してプール内で保管しておき、使用するタイミングでアクティブ化して再利用することで、ゲーム内の負担を軽減させる仕組みです。

例えば、マウスでクリックした場所に以下のようにエフェクトを表示させる処理を作成してみます。

まず、作成したパーティクルシステムのエフェクトをPrefab化しておきます。

そして、空オブジェクトを作成して以下のオブジェクトプールのスクリプトをアタッチしておきます。

using UnityEngine;
using UnityEngine.Pool;

public class EffectManager : MonoBehaviour
{
    public static EffectManager instance;

    // シングルトンを作成
    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }

    ObjectPool<GameObject> effectPool;    // オブジェクトプールの変数を宣言
    public GameObject effect;  // プールの中で管理するエフェクト
    Vector3 effectPos;  // エフェクトを表示させる座標

    void Start()
    {
        // オブジェクトプールのインスタンスを生成
        effectPool = new ObjectPool<GameObject>(
            CreateEffect,       // エフェクト生成の際の処理
            OnGetEffect,        // エフェクトを取り出す際の処理
            OnReturnEffect,     // エフェクトを返却する際の処理
            OnDestroyEffect,    // プールの上限を超えた場合の処理
            true,               // すでにプール内にいるエフェクトを返却した際のエラー表示の有無
            2,                  // 初期のプールの容量
            10);                // プール内の上限数
    }

    GameObject CreateEffect()
    {
        return Instantiate(effect);
    }

    void OnGetEffect(GameObject obj)
    {
        obj.SetActive(true);        // アクティブ化する処理
        obj.transform.position = effectPos;     // エフェクトを指定した位置に表示
    }

    void OnReturnEffect(GameObject obj)
    {
        obj.SetActive(false);   // 非アクティブ化する処理
    }

    void OnDestroyEffect(GameObject obj)
    {
        Destroy(obj.gameObject);    // 破壊する処理
    }

    // エフェクトを取り出すためのメソッド
    public void GetEffect(Vector3 pos)
    {
        effectPos = pos;
        effectPool.Get();
    }

    // エフェクトを返却するためのメソッド
    public void ReleaseEffect(GameObject obj)
    {
        effectPool.Release(obj);
    }
}

オブジェクトプールの作り方については、ここでは省略しておきますが、このスクリプトの中の60行目のGetEffectエフェクトをプールから取り出す処理、67行目のReleaseEffect使い終わったエフェクトをプールに戻す処理となっています。

次に、画面内をクリックした場所にエフェクトを表示させるために、もう一つ空オブジェクトを作成して、以下のスクリプトを紐づけています。

using UnityEngine;
using UnityEngine.InputSystem;

public class EffectGenerator : MonoBehaviour
{
    // クリックした場合の処理
    void OnClick()
    {
        Vector3 clickPos = Camera.main.ScreenToWorldPoint(Pointer.current.position.ReadValue());    // クリックしたワールド座標を取得
        EffectManager.instance.GetEffect(new Vector3(clickPos.x, clickPos.y, 0));   // Z座標を0にした場所にエフェクトを表示
    }
}

7行目にInputSystemでマウスをクリックした場合に実行されるメソッドを記述していて、その中でマウス座標の位置をPointer.current.positionから取得し、GetEffectでその位置にエフェクトを表示させる処理を行っています。

あとは、Prefab化したパーティクルシステムのStopActionの設定を「Callback」に変更しておきます。

そして、このパーティクルシステムに以下のスクリプトを紐づけておきます。

using UnityEngine;

public class EffectController : MonoBehaviour
{
    void OnParticleSystemStopped()
    {
        EffectManager.instance.ReleaseEffect(this.gameObject);
    }
}

5行目で、再生が終了した際に呼ばれるOnParticleSystemStoppedメソッドを定義しておき、この中にReleaseEffectメソッドでプールに返却する処理を記述しておきます。

これでゲームを実行してみると、

マウスでクリックした場所にエフェクトが表示されますが、このエフェクトの再生が終了したら自動的に非アクティブ化されて、再度表示されるタイミングでアクティブ化され、再利用できているのがわかると思います。

まとめ

このページでは、Unityでパーティクルシステムの再生が終了した際に処理を行う方法をまとめていきましたが、いかがでしたでしょうか?

パーティクルシステムの再生が終了した場合の処理は、「StopAction」という設定で行うことができます。

このStopActionは、パーティクルの放出が止まり、全てのパーティクルが消滅した際に実行される処理を選択することができます。

オブジェクトを削除したり無効化するだけでなく、コールバック関数でスクリプトから記述した処理を実行することもできるようになります。

最後までお読みいただきまして、ありがとうございました!

コメント