Search Unity

ParticleSystem indexes / identifying particles (C#)

Discussion in 'Scripting' started by ArchaeopteryxRoboParty, Jul 27, 2015.

  1. ArchaeopteryxRoboParty

    ArchaeopteryxRoboParty

    Joined:
    Sep 15, 2014
    Posts:
    10
    Hi guys,

    I'm attempting to maintain references to individual particles but I'm struggling to come up with a way to do this reliably. There doesn't appear to be any Particle Id, and it seems Shuriken doesn't keep the same array index for a given particle during it's lifetime?
    i.e if a particle dies, it is removed from the GetParticles array and all the other particles shift index accordingly - so the index of a particle could change at any time.

    As a Particle is a struct, there's no way to keep a reference to a particular particle either (if they were classes, this should work).

    I've tried keeping an array of metadata in sync with the GetParticles array (by index), but as Shuriken is a black box I haven't been able to decipher exactly what's going on - sometimes I'm getting array out of bounds errors, sometimes not. I'm guessing Shuriken does some kind of pooling but I'm doing a lot of blind guesswork here.

    Any tips on how to go about identifying unique particles would be much appreciated.
    I'm debating building a custom particle system from scratch to deal with this, but thought it best to check here first!

    Many thanks :)
     
    popMark likes this.
  2. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,444
  3. Strategos

    Strategos

    Joined:
    Aug 24, 2012
    Posts:
    255
    Particle systems are good fun to write, but as it stands you can't get into shuriken to do what you want. Maybe the 5.3 changes will let you but ... who knows.

    How many particles are you dealing with , what do you want to do with them ? Is a particle system the right tool for this job?
     
  4. ArchaeopteryxRoboParty

    ArchaeopteryxRoboParty

    Joined:
    Sep 15, 2014
    Posts:
    10
    Thanks @mgear - I hadn't seen Hydra, it definitely looks promising and access to source would definitely make this a quick job! Shame it's not out yet. It doesn't look like the 5.3 changes will aid this, though they do look generally useful!

    @Strategos: I'm only dealing with a couple of hundred particles at the very most for this particular use case, so not a huge amount. I'm basically building particle trails that can be manipulated, so need to store a history of each particle's position over time (and potentially other properties). As far as I can see, this requires some way to keep references to individual particles. I'm porting from C++ to Unity, and a particle system worked great in that implementation. Each particle had a unique Id there, which made this a pretty simple job.

    I thought array index might do the job here (and it still might...), but it's a bit fickle at the moment due to particle deaths shifting everything in the array so the trails get mixed up. Also, it doesn't seem like there's any way to detect particle birth/death events and as Shuriken removes particles when lifetime == 0 I'm currently checking just *before* a particle dies and attempting to update my indexes to match Shuriken when the particle has actually been removed - which probably adds to the fickle-ness (though this is pretty rough at the moment - there might be a better way?) Thanks :)
     
  5. brn

    brn

    Joined:
    Feb 8, 2011
    Posts:
    320
    Hello,
    Just posting this here with a link to the Unity docs to help out future and previous time travellers.
    About to test it out in practice and will report back if there are any roadblocks

    :)

    https://docs.unity3d.com/ScriptReference/ParticleSystem.SetCustomParticleData.html

    From the Unity Docs

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections.Generic;
    4.  
    5. public class ExampleClass : MonoBehaviour {
    6.  
    7.     private ParticleSystem ps;
    8.     private List<Vector4> customData = new List<Vector4>();
    9.     private int uniqueID;
    10.  
    11.     void Start() {
    12.  
    13.         ps = GetComponent<ParticleSystem>();
    14.     }
    15.  
    16.     void Update() {
    17.  
    18.         ps.GetCustomParticleData(customData, ParticleSystemCustomData.Custom1);
    19.  
    20.         for (int i = 0; i < customData.Count; i++)
    21.         {
    22.             // set custom data to the next ID, if it is in the default 0 state
    23.             if (customData[i].x == 0.0f)
    24.             {
    25.                 customData[i] = new Vector4(++uniqueID, 0, 0, 0);
    26.             }
    27.         }
    28.  
    29.         ps.SetCustomParticleData(customData, ParticleSystemCustomData.Custom1);
    30.     }
    31. }
     
    nazaroth likes this.
  6. jiraphatK

    jiraphatK

    Joined:
    Sep 29, 2018
    Posts:
    300
    Since there seems to be no answer to this, here's my approach.

    Code (CSharp):
    1. public Transform spawnTransform;
    2.     public SpriteRenderer srTemplate;
    3.     public List<SpriteRenderer> sr = new List<SpriteRenderer>();
    4.  
    5.     public ParticleSystem ps;
    6.  
    7.     private ParticleSystem.Particle[] _particles;
    8.     private uint _seedCount = 0;
    9.     private Dictionary<uint, SpriteRenderer> _mapping = new Dictionary<uint, SpriteRenderer>();
    10.  
    11.     private void Start()
    12.     {
    13.         for (int i = 0; i < sr.Count; i++)
    14.         {
    15.             ps.Emit(new ParticleSystem.EmitParams()
    16.             {
    17.                 position = sr[i].transform.position,
    18.                 startLifetime = 2f,
    19.                 startColor = sr[i].color,
    20.                 randomSeed = _seedCount
    21.             },1);
    22.             _mapping.Add(_seedCount, sr[i]);
    23.             _seedCount++;
    24.         }
    25.  
    26.         _particles = new ParticleSystem.Particle[ps.main.maxParticles];
    27.     }
    28.  
    29.     private void Update()
    30.     {
    31.         var pCount = ps.GetParticles(_particles);
    32.  
    33.         for (int i = 0; i < pCount; i++)
    34.         {
    35.             var sprite = _mapping[_particles[i].randomSeed];
    36.             _particles[i].position = sprite.transform.position;
    37.             _particles[i].rotation3D = sprite.transform.localRotation.eulerAngles;
    38.             _particles[i].remainingLifetime = 2f;
    39.         }
    40.        
    41.         ps.SetParticles(_particles, pCount);
    42.     }
    43.  
    44.  
    45.     public void Add()
    46.     {
    47.         var newSR = Instantiate(srTemplate, spawnTransform);
    48.         newSR.transform.localPosition = Random.insideUnitCircle * 5f;
    49.         newSR.color = new Color(Random.value, Random.value, Random.value, 1f);
    50.         sr.Add(newSR);
    51.         _seedCount++;
    52.         _mapping.Add(_seedCount, newSR);
    53.        
    54.         ps.Emit(new ParticleSystem.EmitParams()
    55.         {
    56.             position = newSR.transform.position,
    57.             startLifetime = 2f,
    58.             startColor = newSR.color,
    59.             randomSeed = _seedCount
    60.         },1);
    61.     }
    62.  
    63.     public void RemoveRandom()
    64.     {
    65.         int index = Random.Range(0, _mapping.Count);
    66.         var kv = _mapping.ElementAt(index);
    67.         var seed = kv.Key;
    68.         var spriteRen = kv.Value;
    69.         sr.Remove(spriteRen);
    70.         _mapping.Remove(seed);
    71.         Destroy(spriteRen);
    72.         var pCount = ps.GetParticles(_particles);
    73.         for (int i = 0; i < pCount; i++)
    74.         {
    75.             if (_particles[i].randomSeed == seed)
    76.             {
    77.                 _particles[i].remainingLifetime = 0f;
    78.                 break;
    79.             }
    80.         }
    81.         ps.SetParticles(_particles, pCount);
    82.     }