2
\$\begingroup\$

In my game, I have particles that should spawn at random intervals but with an average rate of x per second.

However, the frame-rate varies from around 60 fps all the way to around 3000 fps. I would like to maintain a variable frame-rate to ensure the game looks as smooth as possible, but this means I cannot simply create particles with probability x each frame:

if (random.Next(100) > x)
{
    // Create particle... 
} 

How can I maintain a constant "real time" drop-rate when the frame rate fluctuates?

Note that I have a variable dt which is the number of seconds since the last frame.

\$\endgroup\$
  • \$\begingroup\$ 3000? What kind of hardware are you targeting? Can the human eye see the difference? (This is not relevant to your current issue; I'm just wondering if it's really worth it...) \$\endgroup\$ – Vaillancourt Jul 7 '15 at 21:29
  • \$\begingroup\$ Well 3000 is unneccessary, but I want to support 144hz monitors properly. I don't want to set the fixed rate that high though, or low-end PCs will struggle to keep up. \$\endgroup\$ – sdgfsdh Jul 7 '15 at 21:30
  • \$\begingroup\$ Kk, I can understand the variable dt, and that's enough for the question :) \$\endgroup\$ – Vaillancourt Jul 7 '15 at 21:46
1
\$\begingroup\$

While this is not a perfect solution, you can say something like:

if (random.NextDouble() / x < dt)
{
    // Create particle... 
}

How this works:

For now, let's assume that you want an average of 1/second (so / x does nothing). If it's been one second since the last frame, you want an average of one particle to appear. random.NextDouble() always generates a number such that 0 <= n < 1, so it will always be less than dt in this case, causing a particle to always appear. If it's been 1/60th of a second since the last frame, dt will be 1/60. random.NextDouble() has a 1/60 chance to be less than 1/60, so on average there will be 1 particle every 60 frames, or 1/second.

Now, let's say that you want 2/second. If it's been 1/60th of a second since the last frame, dt will be 1/60. random.NextDouble() / x (where x == 2) has a 1/30 chance to be less than 1/60, so on average there will be 2 particles every 60 frames, or 2/second.

\$\endgroup\$
  • \$\begingroup\$ This solution only works when x * dt is small. Suppose it were larger than 1; there should be a chance for 2 particles to spawn in one update. \$\endgroup\$ – sdgfsdh Jul 9 '15 at 8:09
  • \$\begingroup\$ @sdgfsdh Yup, that's why I said it's not a perfect solution. \$\endgroup\$ – The Guy with The Hat Jul 9 '15 at 17:09
0
\$\begingroup\$

Would this idea of an accumulator of probability work?

float acc -> particle count accumulator

float x   -> particles per second
float dt  -> number of seconds since last frame

update( dt )
{
  // increase the chance of a particle spawned this update
  acc += x * dt;

  // This case where you run at a very low frame rate, or that you want 
  // A LOT of particles per second
  while ( acc > 1.0 )
  {
    // [spawn a particle]
    acc -= 1.0; // done with this particle
  }

  // now this is to take care of a "random" but still constant over time.
  if ( acc > 0.0 )
  {
    // as the accumulator increases in value, the more chances there is for a 
    // particle to spawn
    float random_value = rnd.next( 0.0, 1.0 ); // random float between 0 and 1
    if ( random_value < acc )
    {
      // [spawn a particle]
      acc -= 1.0;
      // now acc is negative, there will be no chances of spawning until it gets 
      // back above 0.0 which will happen over time. 
    }
  }
}

Keep in mind: totally not tested, maybe very flawed... dunno! I'm just suggesting stuff from the top of my head.

\$\endgroup\$
0
\$\begingroup\$

One simple way would be to adjust the chance of the drop by dt. So instead of accumulators etc. you could do a simple multiplication: drop if dt * random <= threshold.

\$\endgroup\$
0
\$\begingroup\$

Add or subtract a random number from x, and use timers to spawn particles once per second

if(timer >= 1)
{
  int y=//random number
  int xnew = x + y;
  //clear timer
  for(int i; i <= xnew; i++)
  {
    //span particle
  }
}

This will cause the particles to spawn very close together, and then stop for about a second. To space them out more (but not randomly spaced) you can make an array consisting of [1/x, (1+x)/x, (2+x)/x,...(x-1)/x] and

if(timer in array)
{
//spawn particles
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.