Search Unity

How can I play a single particle system in multiple positions on the same frame?

Discussion in 'General Graphics' started by Radiangames2, Nov 28, 2017.

  1. Radiangames2

    Radiangames2

    Joined:
    Aug 22, 2012
    Posts:
    45
    The only relevant thread I can find on this dates back to 2012, so I'm posting a new question. Hopefully this is a solvable problem.

    Here's the situation: If I move and play a particle system on consecutive frames (for sparks/explosions/etc), it behaves as intended. I see two different explosions/etc, and they are part of the same particle system.

    This seems quite a bit more optimal than re-using multiple particle system game objects in my initial tests (which is in turn significantly faster than instantiating and destroying lots of objects). So I want to make use of this as much as possible. However, if I move the particle system on the same frame and play it, all the emissions happen from the last position sent in that frame. And yes, all the particles are simulating in world space (or they would jump around in the case where the particles play quickly in succession).

    So that leads back to my initial question: How do I get the particle system to play multiple times on the same frame from different positions?

    For reference, my code is approximately something like this, called whenever a collision occurs:

    cached_transform.position = new_explosion_position;
    particle_system.Play();

    I'd rather not have to use multiple particle systems or cache the effects for a frame later. For reference, here's the one forum post I found about the subject from 2012 (with Unity saying it will be fixed soon):

    https://forum.unity.com/threads/usi...ystem-to-emit-from-multiple-locations.123365/
     
    crekri likes this.
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,292
    What you are trying to do will not work. The particles are not drawn when you call Play, they exist in a position ready to be drawn during the render phase. So if you keep moving it then it will only draw the last one which is expected. What you could do instead is emit at each of the locations so that particles are spawned at the parts you need them.

    https://docs.unity3d.com/ScriptReference/ParticleSystem.Emit.html
    You dont need to move the particle system, instead feed the new_explosion_position in as one of the Emit params.
     
    Luis0413 and richardkettlewell like this.
  3. Radiangames2

    Radiangames2

    Joined:
    Aug 22, 2012
    Posts:
    45
    Thanks for the reply. Emit might be an option if our particle systems weren't so varied in their shape modules. We have at least 50 unique particle systems that will go through this system, so moving all that data elsewhere is not simple or desired.

    I'll go with the multiple particle systems route, since there's at most 3 or so on the same frame in the cases I've tested so far. Will still have a lot fewer Instatiations and random objects floating around.
     
  4. martinjonsson01

    martinjonsson01

    Joined:
    Jan 2, 2016
    Posts:
    7
    Hello!

    Sorry for reviving an old thread, but I'm having almost exactly the same issue discussed here. The only difference being that I will have a lot more than 3 particle emissions play during the same frame, so instantiating and positioning multiple particle systems would be quite laggy.

    Most of my project is built with DOTS, but since particle systems aren't DOTS-ified yet I still have to keep them as GameObjects (as far as I know).

    Here's my issue:
    I've got a bunch of entities flying around shooting at each other (several thousands at once), and when they are killed I want them to explode. To do this, I've created an ExplosionSystem which runs on the main thread and has a reference to the particle system. The ExplosionSystem is invoked on a bunch of ExplosionEvents that are generated when entities are killed. My ExplosionEvent has two values: the position at which the explosion should occur and the size of the explosion.

    So far I've got two ways of doing this:

    1.
    Code (CSharp):
    1.     protected override void OnEvent(ExplosionEvent explosion)
    2.     {
    3.         _particleSystem.transform.position = explosion.Position;
    4.         _particleSystem.Play();
    5.     }
    The downside of this way being that it can not handle multiple ExplosionEvents per frame, with the upside being that it actually plays the explosion particle system correctly.

    2.
    Code (CSharp):
    1.     protected override void OnEvent(ExplosionEvent explosion)
    2.     {
    3.         var emitParams = new ParticleSystem.EmitParams
    4.         {
    5.             position = explosion.Position,
    6.             startSize = explosion.Size,
    7.             startLifetime = explosion.Size / 5f,
    8.         };
    9.         _particleSystem.Emit(emitParams, 100);
    10.     }
    The upside of doing it this way being that it can handle multiple ExplosionEvents per frame, but with the downside that the particle system is not being run properly.

    What do I mean by it "not being run properly"? Well, from just looking at the particles generated I can see that something is wrong with the .Emit-way of doing it, because while .Play generates a bunch of different particles with different rotations, velocities and sizes, .Emit seems to either generate 100 exactly identical particles, or only one single particle, because that's the way it looks. (I'll add GIFs of both versions if anyone wants clarification of what I mean.)

    If any of you know of a way to either 1. make the .Emit-particles behave like normal .Play-particles, or 2. allow .Play to be executed multiple times per frame at different positions, then I'd appreciate some guidance!

    Note: I'm aware that this could also be done by having a pool of explosion particle system GameObjects that the ExplosionSystem pulls from, which would allow me to run .Play on each particle system from the pool. The reason why I'd rather use a different solution is because I feel like this solution is a bit overengineered, when it feels like I've (hopefully) just missed a parameter somewhere when calling .Emit. If the pool is the best solution though, please do let me know!
     
    TwinCrab likes this.
  5. LaireonGames

    LaireonGames

    Joined:
    Nov 16, 2013
    Posts:
    705
    Just playing around with this. My systems emit the right shape but not consistently. So it claims it emitted at one point, but I see nothing most of the time.

    I think this is because I'm trying to do a lot (say 3 different emit calls per frame as a guess) and its dropping the first 2.

    Anyway as for what your saying, might be because your not accounting for shape. Try adding this:

    emissionParameters.applyShapeToPosition = true;

    Edit: I was being a moron and fixed the bug with my emission (was still trying to move the transform by mistake). All is working fine now
     
    Last edited: Jan 18, 2021
  6. martinjonsson01

    martinjonsson01

    Joined:
    Jan 2, 2016
    Posts:
    7
    Yup, that solved it! I was missing the applyShapeToPosition-parameter.

    Thank you, @LaireonGames!
     
  7. crekri

    crekri

    Joined:
    Sep 7, 2015
    Posts:
    31
    Now that it's almost the end of 2022, do we have any better way to play a particle effect on multiple places simultaneously?

    I have been trying to create my own Emit() method that behaves similarly to the default Play() method - which should account for sub-particle systems, supports bursts, and various other submodules. I am able to get a bare-bone version of it done, but it would break for more complicated effects...

    I would like to see if there's any better way for this issue as of 2022. (And I don't mind buying paid assets as well)