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:
- Gun sound-intervals are not homogen, sometimes the audio distance between shots is longer because the frame-rate is different from the fire-rate Workaround 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
- Your frame-rate will cap your fire-rate when using the traditional approach of shot instantiation
Traditional Shot Instantiation
float fireRate = 50F;
float nextFire = 0F;
void Update(){
if(Input.GetButton("Fire1") Time.time > nextFire){
nextFire = Time.time + (1F/fireRate);
shot();
}
}
- Instantiation is not homogen for shots after the first one if you don’t take precautions
Interpolated Instantiation
The alternative is to create bullets that should have been fired between frames in an interpolated manner
private void InstantiationInterpolation(){
int shotsMissed = (int)(fireTimer/rofTime); //# shot instantiations missed until this frame
float smallestForeshot = fireTimer%rofTime; //time difference from now to the time the LAST bullet should have been instantiated
fireTimer -= shotsMissed * rofTime; //subtract before shotsMissed gets decreased
while(shotsMissed > 0){ //until all missed shots are fired, oldest are fired first
shotsMissed--;
float foreshot = shotsMissed * rofTime + smallestForeshot; //time that has passed after the bullet should have been instantiated
float lerpFactor = foreshot/Time.deltaTime; //calc lerp factor: lerping FROM current TO Last Frame, change that if recoil is calced between shots
InterpolatedInstantiation(foreshot, lerpFactor); //call costum Instantiation
}
}
private void InterpolatedInstantiation(float foreshot, float lerpFactor){
if(GameMenu.instance.bulletInstantiationInterpolation){lerpFactor = 0F;}
Vector3 position = Vector3.Lerp (thisTransform.position, previousPosition, lerpFactor);//position at which this shot would have been instantiated if we hade continous time
Quaternion rotation = Quaternion.Slerp (thisTransform.rotation, previousRotation, lerpFactor);//rotation at which this shot would have been instantiated if we hade continous time
//foreshot is applied in Projectile.cs because missiles may modify startspeed
//Found out distances between shots on low frameRates finally worked when multiplying offset with 2, i dont know why...
//Vector3 instPos = rotation * Vector3.forward * lerpFactor * Time.deltaTime * speed * 2F; //foreshot can be calculated with lerpfactor too
//Vector3 instPos = rotation * Vector3.forward * foreshot * speed * 2F;
...
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
-
- 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)