Hello! I’ve been having problems with the fire-rate for my FPS game. When it is on 60 FPS it fires slower than it should, and at 240 FPS it fires exactly how fast it should. I need it to just match the right fire-rate, which in this case is 700.
My playback seems to be going faster for the 60 FPS test, but it is slower in real time. Here is a link to the game if you wanted to try it in real-time: Bullet Blox - Roblox
Keep in mind that the recoil is different because the line of code that gives it a kick is getting called less often. At least that is what I hope is going on, pretty confident though.
I’ve tried a few different solutions, such as firing the Activate_Weapon() in a for loop rather than when the is_Shooting variable is set to true in the RenderStepped function. Another one I tried was to fire the Activate_Weapon() function via remote function from the server when the tool is activated. It ended up doing the exact same thing. I hope this made sense.
My current code:
-- Viewmodel Handler
function Activate_Weapon()
if inventory.viewmodel and not Shoot_Debounce then
Shoot_Debounce = true
RecoilSpring:AddVelocity(inventory.data.VM_Settings.Recoil_Amount)
task.spawn(function()
local result = Remotes.Functions.ActivateWeapon:InvokeServer(inventory.viewmodel.AimPart.CFrame.Position, inventory.viewmodel.FrontSidePart.CFrame.Position)
end)
--// Cooldown
task.wait(60 / inventory.data.Weapon_Settings.FireRate)
Shoot_Debounce = false
end
end
function UpdateViewmodel (DeltaTime)
if is_Shooting and not is_Sprinting and not is_StartSprinting and not is_Reloading and ammo > 0 then
task.spawn(function()
Activate_Weapon()
end)
end
RunService.RenderStepped:Connect(UpdateViewmodel)
I appreciate all the help I can get. This is probably a simple fix, I hope.
.RenderStepped fires every time a frame is rendered, higher fps = event is fired more. You can account for this as explained in this post so that the fps does not affect fire rate
DeltaTime is how you fix it. You need to pass DeltaTime into your debounce, since DeltaTime is the amount of time since the previous frame your debounce equation should look like
(60 / FireRate)-DeltaTime
Now i could be wrong because i cant cap my framerate to test but im pretty sure thats how it works.
Could be a dumb math problem from me. I’m really weak at that so sorry if all of this is wrong.
This is still definitely a delta time problem though. Try using os.clock like this:
local FireRate = 700
local Time = 60 / FireRate
local LastFired = os.clock()
if os.clock()-LastFired >= Time then
print("Fired")
LastFired = os.clock()
end
I went back to an old script of mine, updated a few things, and hopefully, this should work for you. However, you’ll have to change some more yourself. It works for semi-auto and full-auto, but I didn’t implement any burst-type stuff.
local timeAccumulator = 0 -- Stores accumulated time
task.spawn(function()
game:GetService("RunService").RenderStepped:Connect(function(deltaTime)
local roundsPerMinute = gunset.rpm
local fireInterval = 60 / roundsPerMinute -- Time per shot in seconds
if shooting and not reloading and not running and ammo > 0 then
if timeAccumulator + deltaTime >= fireInterval then
shoot()
timeAccumulator = timeAccumulator - fireInterval
if not gunset.auto then
shooting = false
end
end
timeAccumulator = timeAccumulator + deltaTime -- Accumulate time
-- Enforce fire rate based on accumulator, independent of FPS
while timeAccumulator >= fireInterval do
-- Fire instantly on click and then enforce the fire rate
shoot()
--ammo = ammo - 1
timeAccumulator = timeAccumulator - fireInterval -- Adjust time accumulator for fire rate
end
else
-- Reset accumulator when not shooting
--timeAccumulator = timeAccumulator + deltaTime
if timeAccumulator <= fireInterval then
timeAccumulator = timeAccumulator + deltaTime
end
end
--timeAccumulator = timeAccumulator + deltaTime
end)
end)```
So, I have traced it back to be a problem with my server script, or at least when I fire the event. I’m guessing that it adds a delay, but isn’t task.spawn supposed to create a new thread? I’m sorry if I’m being stupid and this is a simple fix, I’m kind of tired.
function Activate_Weapon()
if inventory.viewmodel and not Shoot_Debounce then
Shoot_Debounce = true
RecoilSpring:AddVelocity(inventory.data.VM_Settings.Recoil_Amount)
--// Actions
recoil_Goal = CFrame.Angles(0, math.rad(math.random(-2, 2)), 0)
task.spawn(function()
--Remotes.Events.ActivateWeapon:FireServer(inventory.viewmodel.AimPart.CFrame.Position, inventory.viewmodel.FrontSidePart.CFrame.Position)
end)
--// Cooldown
task.wait(60 / inventory.data.Weapon_Settings.FireRate)
Shoot_Debounce = false
end
end
Firing the server WILL add a delay, and spawn won’t technically fix it. You can always handle the rays on the client and verify the information on the server, or you can let the server handle the rays. Either one will present different risks and issues that will have to be verified on the server. Using something like a bindable event will force the client to wait on the server, further adding delay. Remote events would be my recommendation, along with handling rays on the client, especially for visual feedback while verifying the hits and rays on the server.
Ok, I just got it fixed! The problem was solved with the delta time applied to the wait that @Daniel1154 pointed out, and I had some code that enables/disables the muzzle effects that would fire every frame. The code that fired every frame was the main problem, I moved it to the Activate_Weapon function and it removed the delay. It was bad practice to update it every frame anyways, I just didn’t think it would delay the script that much. I now feel like an idiot.