2

I'm trying to change my particle system function to a pooling instead of instantiating everytime. I want to reuse the particles. How is that possible? I have no idea how to start although i watched the unity tutorial but somehow it's still unclear. maybe because im calling the particle system function in other classes it's confusing me somehow.

public ParticleSystem[] Myeffects;


public void Particle(int particleNum, Vector3 Pos)
{
    if (Myeffects != null && Myeffects[particleNumber] != null )
    {
        if (Myeffects[particleNumber].isPlaying)
            Myeffects[particleNumber].Stop();

        ParticleSystem temp = Instantiate(Myeffects[particleNum], particlePos, new Quaternion()) as ParticleSystem;

        temp.Play();
    }
}
}
John
  • 141
  • 4
  • 12

1 Answers1

3

First of all, Select your Particle System prefab/TNT then make sure that Play On Awake is unchecked. The pooling script below is dedicated tricky way to accomplish that. It will create an array of ParticleSystem specified then re-use them. Notice that ParticlePool does not inherit from MonoBehaviour, so make sure to copy it directly.

using UnityEngine;
using System.Collections;
using System;

public class ParticlePool
{
    int particleAmount;
    ParticleSystem[] NormalParticle;
    ParticleSystem[] TNTParticle;

    public ParticlePool(ParticleSystem normalPartPrefab, ParticleSystem tntPartPrefab, int amount = 10)
    {
        particleAmount = amount;
        NormalParticle = new ParticleSystem[particleAmount];
        TNTParticle = new ParticleSystem[particleAmount];

        for (int i = 0; i < particleAmount; i++)
        {
            //Instantiate 10 NormalParticle
            NormalParticle[i] = GameObject.Instantiate(normalPartPrefab, new Vector3(0, 0, 0), new Quaternion()) as ParticleSystem;

            //Instantiate 10 TNTParticle
            TNTParticle[i] = GameObject.Instantiate(tntPartPrefab, new Vector3(0, 0, 0), new Quaternion()) as ParticleSystem;
        }
    }

    //Returns available GameObject
    public ParticleSystem getAvailabeParticle(int particleType)
    {
        ParticleSystem firstObject = null;

        //Normal crate
        if (particleType == 0)
        {
            //Get the first GameObject
            firstObject = NormalParticle[0];
            //Move everything Up by one
            shiftUp(0);
        }

        //TNT crate
        else if (particleType == 1)
        {
            //Get the first GameObject
            firstObject = TNTParticle[0];
            //Move everything Up by one
            shiftUp(1);
        }

        return firstObject;
    }

    //Returns How much GameObject in the Array
    public int getAmount()
    {
        return particleAmount;
    }

    //Moves the GameObject Up by 1 and moves the first one to the last one
    private void shiftUp(int particleType)
    {
        //Get first GameObject
        ParticleSystem firstObject;

        //Normal crate
        if (particleType == 0)
        {
            firstObject = NormalParticle[0];
            //Shift the GameObjects Up by 1
            Array.Copy(NormalParticle, 1, NormalParticle, 0, NormalParticle.Length - 1);

            //(First one is left out)Now Put first GameObject to the Last one
            NormalParticle[NormalParticle.Length - 1] = firstObject;
        }

        //TNT crate
        else if (particleType == 1)
        {
            firstObject = TNTParticle[0];
            //Shift the GameObjects Up by 1
            Array.Copy(TNTParticle, 1, TNTParticle, 0, TNTParticle.Length - 1);

            //(First one is left out)Now Put first GameObject to the Last one
            TNTParticle[TNTParticle.Length - 1] = firstObject;
        }
    }
}

Then, your ParticleHolder script should be updated with the code below. That's it. No more instantiation.

public class ParticleHolder : MonoBehaviour
{

    public ParticleSystem[] effects;
    ParticlePool particlePool;

    void Start()
    {
        // 0 = Normal crate
        // 1 = TNT crate
        particlePool = new ParticlePool(effects[0], effects[1], 5);
    }

    public void playParticle(int particleType, Vector3 particlePos)
    {
        ParticleSystem particleToPlay = particlePool.getAvailabeParticle(particleType);

        if (particleToPlay != null)
        {
            if (particleToPlay.isPlaying)
                particleToPlay.Stop();

            particleToPlay.transform.position = particlePos;
            particleToPlay.Play();
        }

    }
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • You mean 10 different types of particles? I thought there is only 2 types? – Programmer Jul 09 '16 at 19:40
  • Yes, I did say instantiate 10. After more testing I decided to instantiate only 5. You can see where I did `particlePool = new ParticlePool(effects[0], effects[1], 5);`. The five is enough. It will re-use those 5. You don't need more than that. Test it and see for yourself. – Programmer Jul 09 '16 at 19:46
  • Read the the comment on it. It is very commented. Instead of disabling and enabling the GameObject like Unity did, which is also costly, it will pick the first GameObject in the array when `getAvailabeParticle` is called then move it to the last array index. Basically, a different GameObject is used each time `getAvailabeParticle` is called. It keeps shuffling moving them up to make sure that the current particle will get enough time to finish playing. – Programmer Jul 09 '16 at 20:23
  • This type of pooling is good for particles. Look here http://stackoverflow.com/a/37516378/3785314. I first used it here to answer a question. – Programmer Jul 09 '16 at 20:24
  • There are only 10 particles in the scene. 5 for the normal particle and 5 for tnt particles. There is nothing wrong with that. Assuming you have 100+ particles then it is worth disabling them.You are fine. – Programmer Jul 09 '16 at 20:30
  • Hey @Programmer Are you available for one more issue im facing? – John Jul 10 '16 at 11:36