Search Unity

How to resume a paused ParticleSystem that has been stopped without emitting new particles?

Discussion in 'Scripting' started by Michael-Ryan, May 10, 2020.

  1. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    Given a ParticleSystem that loops indefinitely or has a very long duration, when I want to gracefully end the particle emission, I call ParticleSystem.Stop(). By default, that stops emitting particles, but allows the existing particles to fade away.

    With such a ParticleSystem, if I want to pause the emission of new particles and freeze the previously emitted particles, I call ParticleSystem.Pause(). That works fine. It stop emitting and the existing particles freeze in place. Calling ParticleSystem.Play() resumes the emission where it left off, and existing particle begin to dissipate again.

    How do I handle the situation where I want to STOP a particle system from emitting more particles and allow the existing particles to dissipate gradually, PAUSE the system to freeze those particles in place and then RESUME the dissipation without restarting the emission of new particles? Calling ParticleSystem.Play() seems to be the only way to resume the system, but that start emitting new particles.

    -----

    There are some states that can be checked. For the simple example of just pausing and resuming, things work out okay. But notice that ParticleSystem.Pause() doesn't just set "isPaused" true, it also sets "isPlaying" and "isEmitting" to false, which makes it difficult to even determine what systems have been previously stopped.
    • Before pausing: IsAlive isPlaying isEmitting isPaused isStopped
    • After pausing: IsAlive isPlaying isEmitting isPaused isStopped
    • After resuming: IsAlive isPlaying isEmitting isPaused isStopped
    When a ParticleSystem has been stopped before pausing but while there are existing particles yet to dissipate, it shows that it's still playing, no longer emitting, but also "isStopped" is false while there are still particles in the air:
    • Before pausing: IsAlive isPlaying isEmitting isPaused isStopped
    • After pausing: IsAlive isPlaying isEmitting isPaused isStopped
    • After resuming: IsAlive isPlaying isEmitting isPaused isStopped ( this is the problem)
    So how do I get the ParticleSystem to resume only the existing particles without resuming the emission of new particles?

    I've worked around this by storing the original ParticlesSystem.isEmitting state and then after calling Play() to resume the particle dissipation (and emission), I immediately call Stop() if the stored isEmitting value is false. This makes the "after resuming" match the "before pausing" state, but it seems like there should be an easier way to handle this situation.

    I considered looking into some way to fast-foward or advance the ParticleSystem to the end of its duration so that it stops emitting naturally, but that won't help systems that are set to loop indefinitely, and it might actually start the ParticlesSystem emission over from the beginning.

    I need to be able to stop the emission of new particles and later pause and resume the existing particles without starting the emission back up.

    Does anyone have a better solution?
     
    Last edited: May 10, 2020
    matronator and SamFernGamer4k like this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    The ParticleSystem is pretty configurable, so I think it does fall to you to adjust the parameters you want to get the effects you need. I use ParticleSystems in a variety of ways, for instance:

    - continuous smoke or a scrolling starfield (simplest): turn it on, rate-over-time, let it roll and loop

    - bullet splashes: use world coordinates, rate-over-time to zero, when the bullet hits, move the particle system to the impact, call emit for the amount I want; If two bullets hit one after the other, just move it again and emit: the world coordinate positions will leave the old particles in place to live their lives out (for conical splashes: align it to the normal too)

    - bullet streaks: set rate-over-time to zero, set rate-over-distance to density of bullet streaks, set color over lifetime to a nice fade-off alpha ramp

    Thinking about it, the only time I disable a ParticleSystem is if it is configured to emit (over distance or time) and I need to move it around somewhere else, such as after spawning and positioning. If you move it without turning it off, it will leave streaks.

    I don't think I have ever stopped a particle system in code; I just either Destroy it when done, or set its rate(s) to zero until I need it again.
     
  3. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    What do you mean by "set its rate to zero"? Are you referring to the Emission module? How do you restore the rate unless you keep track of the original value?

    I'm looking on one particular particle that was setup, and the "Emission" module has various bursts at different times, while the "Rate over Time" is 0. Others might use "Curves" or "Random Between Two Constants", or "Random Between Two Curves". Are we expected to store all of those values so they can be restored.

    I'm dealing with a "generic" component that pauses and resumes object components. It generally don't keep track of initial values for various things, and it deals with all sorts of objects. For example, with AudioSources, it calls Pause, UnPause. It doesn't know if it's a projectile that moves, a stationary explosion, or a splash in a puddle.

    The ParticleSystem API includes Play, Pause, and Stop. The Stop method even has a parameter override that allows you to specify the ParticleSystemStopBehavior: StopEmitting (default) and StopEmittingAndClear, which stops the emitting and removes existing particles. Ideally there would be a Start method override that would allow you to only resume the existing particles, or a better option would be to have a Resume or UnPause, like the AudioSystem class.

    My current solution of storing just the "isEmitting" state and immediately calling Stop() after Play() seems far less complicated and a safer way to resume just the existing particles when unpausing the game.

    In short, when the system is paused, shouldn't there be a way to resume it where it left off? If the system isn't emitting particles when it's paused (but still has existing particles), what is the proper way to resume or unpause the system without it starting to emit particles again?

    The Stop method is clearly the intended way to stop emission. It makes no sense to require us to somehow adjust the emission rate and handle four different modes of emission in the Emission module.
     
    Last edited: May 10, 2020
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Ah well, that makes sense... I haven't done partial-game pausing like that. When I do a game-wide pause I just set time scale to zero and pretty much 100% of stuff does what it should, particles, trails, etc.
     
  5. matronator

    matronator

    Joined:
    Feb 4, 2022
    Posts:
    3
    Actually time scale doesn't seem to affect already spawned particles as they seem to continue to live out their lifetime even after setting time scale to zero. I also have to additionally pause to stop them in place.

    Would love to see if someone knows the solution to what OP's looking for.
     
    ben_hip likes this.