My game has a special movement system which allows player to gain movement speed if they timed it right to jump when they land from the previous jump (similar to bhopping). Here’s the pseudo code:
repeat RunService.RenderStepped:Wait() until
tick() >= Minimum Activate Time or Character Is Jumping
-- The player jumped again or timed out, player did not jump after he/she has landed.
if -- player jumped again then
-- Gain Speed
end
Recently I found that players with higher FPS do have an advantage since I am using RenderStepped:Wait() which runs faster when the game runs in a higher FPS.
In other scenarios that have to combat with high FPS issue, the solution will probably be multiplying the values to the delta time such that the code can run smoothly in higher FPS. Such as moving a local part at a same speed but in different FPS. You won’t want a player to see a part moving in 60 FPS while he/she is in a higher FPS.
However, in my case, I’d like to synchronize it to 60 FPS. This is similar how CS:GO has different tick rate servers such that b-hopping is easier on 128 ticks server than 64 ticks. I want the game to count and run the pseudo code above in a “60 FPS rate” such that everyone has a fair chance to use this mechanic. I’m currently thinking changing it from RenderStepped:Wait() into wait(1/60) and I can’t think of any other solution, are there any alternatives?
local function wait(seconds: number)
seconds = seconds or (1 / 60)
local deltaTime = 0
while (deltaTime < seconds) do
deltaTime += game:GetService("RunService").Heartbeat:Wait()
end
return deltaTime
end
I’ve always used this function, the good thing about it is that the inaccuracy for it is 0.1, while the inaccuracy for the built-in wait() is about 0.3.
Now, for what you’re looking, this fits because since it uses Heartbeat, it can wait a minimun of 1/60, while wait() can only wait 1/30 because Roblox’s task scheduler runs at 30 Hz.
(I’d also try looking for a non-polling way, for example using the .Jumped event or .StateChanged event)
You have to multiply the speed with delta time since delta time is connected to frame rate, parts won’t move faster/slower frame rate just adds more frames in between position 1 and position 2.
With higher fps they get more frames to input a key and gain movement speed
With lower fps they get less frames to input a key and hence suffers as they have time the jump more accurately:
Reminds of krunker io they also have the same issue last time I remember.
You could use wait() which could force the minimum wait time 0.02999 (approx. 0.03) (punish the higher fps players decreasing the amount of inputs they have, doesn’t seem like a good idea) but it could also suffer from lag as it’s the minimum wait time so lower fps players still suffers.
Otherwise based on the diagram assuming it’s correct hopefully you could also increase the minimum activate time to compensate for the person with lower fps by adding +1 average frame so they can time to jump easier.
Well, that’s exactly what I’m trying to do! I’m trying to synchronize every player has the same “60 FPS polling” such that higher FPS players does not gain advantage by having more frames to input. I’m trying to make the polling run in a 60 FPS rate despite the player having even higher frames.
If you insist on that, I can think of only one solution:
We have 2 variables: delta60 and deltaCurrent. delta60 is initialized as 1 / 60 and deltaCurrent as 0.
Every time the .RenderStepped event is run, it adds the delta time argument to deltaCurrent, then checks if deltaCurrent < delta60.
If it is true, return. Else, do whatever you need to do, then set deltaCurrent to 0.
As an example, say we have player A at 60 FPS and player B at 120 FPS.
First frame:
Player A:
deltaCurrent(0) + 0.016(1/60) = 0.016 deltaCurrent(0.016) is bigger/equal than delta60(0.016), continue
…
deltaCurrent = 0
Player B:
deltaCurrent(0) + 0.0083 (1/120) = 0.0083 deltaCurrent(0.0083) is smaller than delta60(0.016), return
Second frame:
Player A:
deltaCurrent(0) + 0.016(1/60) = 0.016 deltaCurrent(0.016) is bigger/equal than delta60(0.016), continue
…
deltaCurrent = 0
Player B:
deltaCurrent(0.0083) + 0.0083 (1/120) = 0.016 deltaCurrent(0.016) is bigger/equal than delta60(0.016), continue
…
deltaCurrent = 0
In code, this would be:
local deltaCurrent = 0
local delta60 = (1 / 60)
RunService.RenderStepped:Connect(function(deltaTime: number)
deltaCurrent += deltaTime
if (deltaCurrent < delta60) then return end
-- ...
deltaCurrent = 0
end)
For your implementation, that’d be something like:
local function reproduction()
local connection: RBXScriptConnection
local deltaCurrent = 0
local delta60 = (1 / 60)
connection = RunService.RenderStepped:Connect(function(deltaTime: number)
deltaCurrent += deltaTime
if (deltaCurrent < delta60) then return end
-- pseudo code
if (playerJumping) then
if (playerJumpingAgain) then
-- Give them more speed
end
elseif (tick() >= minimunActivationDistance) then
connection:Disconnect()
end
deltaCurrent = 0
end)
end
But please keep in mind this can make players with FPS of numbers not divisible by 60 have not smooth transitions in whatever you’re doing. Although that’s what you call a “punishment”, I suppose.
The example I gave was in function format, you can adapt that to whatever you need. (^▽^)
There’s one small problem with the method above: the player gets 3 frames to jump before it times out on 60 FPS. However with higher FPS, it’s ranged between 3 to 4 FPS and 4 FPS gaps happen often.
I replaced RenderStepped by using :Wait() and it’s somehow solved… not sure is it a good solution tho. repeat deltaCurrent += RunService.RenderStepped:Wait() if deltaCurrent > delta60 then print("jump now") deltaCurrent = 0 end