Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

The Problem of variable time steps

Discussion in 'Scripting' started by Marrt, Aug 27, 2016.

  1. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    I wanted to hear some opinions on the inconsistencies that arise within most game engines considering that they use variable frame-rates for game logic. If you ever tried to create a Gun with a high fire-rate in Unity you may have noticed these problems for all shots after the first one:

    1. Gun sound-intervals are not homogen, sometimes the audio distance between shots is longer because the frame-rate is different from the fire-rate
    Use specifically lengthened looping sounds for automatic fire or do some cumbersome audio programming for precise timing -which is pure pain and never works out, for me at least
    2. Your frame-rate will cap your fire-rate when using the traditional approach of shot instantiation
    Code (CSharp):
    1. float fireRate = 50F;
    2. float nextFire = 0F;
    3. void Update(){
    4.     if(Input.GetButton("Fire1")  Time.time > nextFire){
    5.         nextFire = Time.time + (1F/fireRate);
    6.         shot();
    7.     }
    8. }    
    3. Instantiation is not homogen for shots after the first one if you don't take precautions
    The alternative is to create bullets that should have been fired between frames in an interpolated manner
    Code (CSharp):
    1. private void InstantiationInterpolation(){
    2.        
    3.         int shotsMissed    = (int)(fireTimer/rofTime);    //# shot instantiations missed until this frame
    4.         float smallestForeshot = fireTimer%rofTime;    //time difference from now to the time the LAST bullet should have been instantiated
    5.         fireTimer -= shotsMissed * rofTime;            //subtract before shotsMissed gets decreased
    6.        
    7.         while(shotsMissed > 0){                        //until all missed shots are fired, oldest are fired first
    8.             shotsMissed--;
    9.             float foreshot = shotsMissed * rofTime + smallestForeshot;    //time that has passed after the bullet should have been instantiated
    10.             float lerpFactor = foreshot/Time.deltaTime;                    //calc lerp factor: lerping FROM current TO Last Frame, change that if recoil is calced between shots
    11.             InterpolatedInstantiation(foreshot, lerpFactor);            //call costum Instantiation
    12.         }
    13.     }
    14.    
    15.     private void InterpolatedInstantiation(float foreshot, float lerpFactor){
    16.        
    17.         if(GameMenu.instance.bulletInstantiationInterpolation){lerpFactor = 0F;}
    18.         Vector3        position = Vector3.Lerp        (thisTransform.position, previousPosition, lerpFactor);//position at which this shot would have been instantiated if we hade continous time
    19.         Quaternion    rotation = Quaternion.Slerp    (thisTransform.rotation, previousRotation, lerpFactor);//rotation at which this shot would have been instantiated if we hade continous time
    20.            
    21.         //foreshot is applied in Projectile.cs because missiles may modify startspeed  
    22.         //Found out distances between shots on low frameRates finally worked when multiplying offset with 2, i dont know why...
    23.         //Vector3        instPos  = rotation * Vector3.forward * lerpFactor * Time.deltaTime * speed * 2F;    //foreshot can be calculated with lerpfactor too
    24.         //Vector3        instPos  = rotation * Vector3.forward * foreshot * speed * 2F;
    25.     ...  

    So basically, every game that does not use a fixed-update-interval and ties it to a regular real-world-time-interval (which is every game after 2000?) becomes an indeterministic mess if viewed through the lens perfectionism, but well, we knew that didn't we?

    Note:
    - Using physics is no fix for the audio because it does NOT run at regular real-world-time-intervals
    - 2. and 3. can be avoided by using physics, but only if your aim is dependent on rigidbody rotation and you are using an input wrapper for fixed update (like that one: http://forum.unity3d.com/threads/the-truth-about-fixedupdate.231637/page-2#post-2739285)
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I'm curious why you need a weapon that fires more then 60 times per second. Simply solve the issue with game design. Almost all of your issues disappear if you drop your fire rate down to ten times per second or so.

    According to google the fastest machine gun fires at 50 rounds per second. So 10 rounds per second is probably in the ball park for most weapons.
     
  3. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    If you fire at steady firing rate, you expect that the bullets are evenly spaced. The problem arises when you firing rate is much higher than the frame rate. If you instantiate your bullets naively (without any correction), you are going to miss some bullet and they won't be evenly space... so don't do that.

    Instead, you would need to apply some corrections to make a believable high firing rate. For instance you can keep track of the last fired bullet. Then at each frame, you just have to fill up the gap to that last bullet, that is, compute how much bullet should have been fired, instantiate and place them accordingly (you know their velocity, when they should have been fired, so you can compute their current position). This way no bullet is missed and they are correctly placed, given the illusion that they are fired at a high rate.

    About the sound, you don't have to play a distinct sound for each single fired bullet, rather play a looped sound that already contains several bullets firing, and if the firing rate is high enough, the player won't notice if they are sync-ed or not.
     
    Last edited: Aug 27, 2016
    Kiwasi likes this.
  4. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    612
    It is also inconsistent for lower fire rate when shoots have different amount of frames between them due to timing interferences, also lower fire rate only does not solve what happens when the frame rate goes down

    That is what i proposed in my solutions within the Spoiler Tags. Also the sound fix, but i can tell you that player will notice, sync, ever played hawken? Maybe an additional side thought to that: Multiplayer: if you e.g. would deliberately create a framerate drop on your pc after firing in client side detection netcodes (like overwatch) you might instantiate all bullets instantly between two frames hitting the same rigidbody within one frame creating instant kills before the receiver had the chance to get the first bullet (enables cheating)

    And what about the recoil for the inbetween-shots? Or recoil in general, e.g. i coded a physical based recoil system where guns have a mass and a PID-Controller that drives them back to the Aimpoint. I need to manually check by interpolation where the tip of the gun was pointing to at the moment the gun would have released a shot, or the recoil patterns would vary greatly with frame rate These are just things that cross my mind and require a lot of thought and the right implementation. I am not building an FPS, i just tackled a recoil implementation recently and these things bugged me.

    If you want to check it out: http://marrt.elementfx.com/?page=7 (note: i unknowingly broke the target mini game for the current build)