Hey all, so I’ve been trying to make my custom game engine FPS unlocker proof, as the game currently relies on the client’s framerate to update the simulation, and if the user uses an FPS unlocker, the game will run above 60 Hz (which will speed up the simulation and make the game appear sped up)
Current method:
-- Runs at 60 Hz (Assuming an FPS unlocker isn't being used)
RunService.RenderStepped:Connect(function()
UpdateSimulation()
Canvas:Update() -- Render the image
end)
Attempt at framerate cap:
-- With this code, the simulation now only seems to update at around 40 Hz??
local UpdateRate = 1 / 60 -- 60 FPS/Hz
local LastFrame = os.clock()
RunService.RenderStepped:Connect(function()
if os.clock() > LastFrame + UpdateRate then
LastFrame = os.clock()
UpdateSimulation()
end
Canvas:Update() -- Render the image
end)
Can someone explain to me why this is causing unpredictable results and my game is now running below 60 Hz with this applied? It really shouldn’t be and i’m really confused as to why this is happening. I could also just be missing something entirely.
I can’t just use a while loop in this case. I still the need to game to use RenderStepped, but with a limit on the amount of times that event can fire (such as someone using an FPS unlocker). The update rate should be able to go below 60, but not above if that makes sense
RunService.RenderStepped:Connect(function()
if os.clock() > LastFrame and os.clock() == LastFrame + UpdateRate then
LastFrame = os.clock()
UpdateSimulation()
end
Canvas:Update() -- Render the image
end)
I think that should work but I’m not sure,
Or maybe using 2 RenderStepped connections but using :ConnectParallel()
It’s 100% sure that the os.clock() will be greater than LastFrame and you can’t check if it will be equal cause there’s litteraly no chance that it would be equal the script of @Ethanthegrand14 seems to be good, I don’t really get why it does not work …
If you want your game to run at a fixed timestep you should do something like this.
local Timestep = 1/60
local Accumulator = 0
RunService.RenderStepped:Connect(function(dt)
Accumulator += dt
while Accumulator >= Timestep do
UpdateSimulation(Timestep)
Accumulator -= Timestep
end
Canvas:Update() -- Render new game state.
end)
But you should really be writing your UpdateSimulation() function to handle a variable delta time anyway.
local UpdateRate = 1 / 60 -- 60 FPS/Hz
local LastFrame = os.clock()
RunService.RenderStepped:Connect(function()
local sum = LastFrame + UpdateRate
local difference = os.clock() - sum
if difference > 0 then
LastFrame = os.clock() - difference
UpdateSimulation()
end
Canvas:Update() -- Render the image
end)
you need to take into account the time error i think? which you have not done.
Weird, honestly. I think you are much better off adjusting your simulation code to be FPS independent and scale it according to the deltaTime between each frame, it may be easier than you think!