I’ve been attempting to create a formula for a Rounds-Per-Minute Fire Rate system but can’t seem to wrap my head around the math (I am aware that this is probably something simple I’ve missed)
So in simple terms, I need it to call a function once a second for 60 RPM, twice a second for 120 RPM, etc. I am aware this will be using Time.DeltaTime but I can’t seem to figure out how to write out the formula.
UPDATE: Countdown = (RPM/60) doesn’t actually work. It LOOKS like it would but any number above 60 causes a slower ROF and any below leads to a faster one.
simpler than you think!!! Adding time.deltatime every frame takes 1 second to count to 1.
so really all you need to do is devide to get rounds per second and use a timer like this and it should be accurate!!!
public float rpm=60;//<--rounds per minute here
float timer=0;
void Start(){
// add this line!!!!!
rpm = 60.0f / rpm;
// now devide to get rounds per second
rpm = rpm / 60f;
}
void Update(){
if(Input.GetKey("space")){
timer-=Time.deltaTime;
if(timer<0){
timer+=rpm;
//fire here!!!!!!!!!!!!!!!
}}}
You need to use a “catch-up” loop. That’s basically how FixedUpdate and the physics system is implemented. I created a helper class on the wiki called CustomFixedUpdate. This class basically implements the same mechanics as Unity uses for the physics time step.
You simply call Update on a CustomFixedUpdate object and it will make sure you get your desired update rate.
However keep in mind that when fireing actual physical bullets the last instantiated bullet might still be at the same position because it might fire two or even more bullets during a single frame. That means the bullets aren’t evenly spaces when they fly through the scene. However if you fire a hit-scan weapon there’s no problem to fire at a rate of 10000 shots per sec. At a frame rate of 60fps the class would fire about 166 bullets each frame.
edit
If you don’t like to use that class, you can do it manually in place:
public float rpm = 120;
private float coolDownTimeout =0;
void Update()
{
if (Input.GetButton("Fire1"))
{
Fire();
}
else if (Time.time > coolDownTimeout)
{
coolDownTimeout = Time.time;
}
}
void Fire()
{
float dt = 60f / rpm;
while(Time.time >= coolDownTimeout)
{
coolDownTimeout += dt;
FireBullet();
}
}
void FireBullet()
{
// fire one shot
}
Note the else statement is important. Otherwise when not fireing it would accumulate unlimited shots until you fire again. At that time it would burst out as many shots as if you hadn’t stop fireing in the first place -.-. The else statement makes sure to keep the timeout equal to the current time when not fireing .
This does work with any firerate. Even 0.2 rpm or 18000rpm (==300 rounds per second) would work