In my game, there’s projectiles. On the server, an invisible “real” part is used for handling hit detection, and a remote is fired to every client which creates their own visible “fake” part. Movement for the projectiles, both client and server, is handled like this.
--This is the code for the client-projectile movement
local fakeProjectiles : BasePart = {};
function moveProjectiles()
for _, fakeProjectile in next, fakeProjectiles do
fakeProjectile.Position += fakeProjectile.CFrame.LookVector * 5;
end
end
while true do
moveProjectiles();
task.wait();
end
The problem is that task.wait() does not wait as long as it does on the server, and if you use an FPS unlocker like I do, the projectiles on the client outspeed the actual projectiles by a lot. None of the RunService events seem to change this, as task.wait() is based off of RunService.
The RunService events and task.wait both return information regarding how much time has passed (since the last event in the case of RunService or since the call was made in the case of task.wait). This information can be used to move your projectiles at a rate that is invariant from the framerate.
For instance, this modified version of your code would move the projectiles forward at 5 studs-per-second regardless of the framerate.
local fakeProjectiles : BasePart = {};
function moveProjectiles(delta : number)
for _, fakeProjectile in next, fakeProjectiles do
fakeProjectile.Position += fakeProjectile.CFrame.LookVector * (5 * delta);
end
end
game:GetService("RunService").Heartbeat:Connect(moveProjectiles)
As @MysteriousVagabond said, you should use the delta time argument passed with all RunService events, as well as task.wait
local ActualWaitedTime = task.wait(1)
print(ActualWaitedTime)
--Will not print exactly 5, because it's the exact amount of time it waited
--which can have a slight deviation
Also, you could just, use task.wait’s wait argument? That would also mitigate the issue because then you wouldn’t be relying entirely on the client’s framerate, as Roblox will try to wait as close to the wait time as possible instead of just 1 Heartbeat event.