(Rapid fire) How to accurately wait for a very short amount of time?

I’m trying to script a rapid-firing gun. I use a CoRoutine to handle one shot, and then use WaitForSeconds(delayBetweenShots) before I can fire again. However, with a gun that shoots 16 rounds per seconds, that’s a delay of only 0.0625 seconds, far too short for WaitForSeconds. I wrote a simple test script and indeed noticed that WaitForSeconds is inaccurate for short timespans because it only checks if the value has been reached after the last frame has finished.

Is there a (better) way to have (reasonably) time-accurate rapid-fire?

I think this depends on exactly what you’re looking to do. If you look at it on the basis that your framerate is your primary limitation, then there are certainly numerous ways to try and make it work.

Regardless of your approach, you’re still going to wind up at the mercy of Unity’s main Update thread, but options to get around it could include:

  1. Counting up deltaTime and generating your bullets based on how much of a backlog you’ve accumulated. This can be further modified by placing each bullet’s initial location (as applicable) relative to how far off from its own personal timing it’s become (i.e. if 0.0627 second(s) has passed, start the bullet at a position simulating 0.0002 second(s) travel time). Additional tests would probably be necessary in case framerate would result in bullets starting beyond a nearby target.

  2. In the case of multiplayer intent, tell the server when the first shot is fired and it can follow the procedure of “1)” itself.

  3. For the timing itself, an alternative may be able to be managed using System.DateTime in an alternate thread, but then you may run into timing desynchronization issues if a poor framerate causes Time.time to stall and fall behind real time. This approach would likely be able to get the most accurate timing, without need to depend on Unity’s performance, but it would still be limited on when information can be retrieved again by the main game thread.

Anyway, that’s my input on it – I hope there are better solutions possible, but if so, I haven’t thought of 'em yet!

if you have to fire more than one bullt per frame wich is your limitation, you can get around it

by example

float firingSpeed = 0.4f;
float shooted = 0;
float firingStartTime;

bool shooting = false;

void startShooting()
{
shooting = true;
shooted = 0;
firingStartTime = Time.time;
}

void stopShooting()
{
shooting = false;
}

void Update()
{
    if(shooting)
    {    //calculate how many bullets to shoot this frame. this should work, i made this on the fly
          float temp =  ((Time.time - firingStartTime)/firingSpeed) - shooted
           for(float i = 0; i < temp; i++)
           {
               shooted++
               //your code to create bullets
           }
    }

}

because of the nature of floats and divisions, you may have a small margin of error in the number of bullet shooted;
You can use decimal if you are good with it on performance side;

You can use a CustomFixedUpdate routine which basically does what coolraiman has in his answer. My CustomFixedUpdate class allows you to add as many fixed update method you like with any interval you like. 10000 calls per second is also possible. It uses the same approach as Unity’s FixedUpdate method, just in a variable / customizable way.

However this approach has a little problem when you’re firing actual physics objects at a high rate (greater than framerate) as those created during the same frame will be spawned at the same position. As long as the bullet can’t collide with other bullets this shouldn’t be a problem. So using a bullet layer that doesn’t collide with itself should fix the problem.

All you have to do is calling “Update” on the CustomFixedUpdate object every frame while you want to fire.

You’ll want to take advantage of Time.deltaTime. I’d try something like this:

public float timeSinceLastShot = 0f;
public float timerBetweenShots = 0f;

void Update(){
timeSinceLastShot+=1*Time.deltaTime;//Update counter
if(timeSinceLastShot=>timeBetweenShots){//If it's been long enough to shoot again
shoot();//Fire the weapon
timeSinceLastShot=0f;//Reset the timer
}

Time.deltaTime makes things framerate dependent, so they’re more reliable. There’s more info on Time.deltaTime over here: Unity - Scripting API: Time.deltaTime

Hope this helps!