I have a ship that can be piloted by a player.
- The ship has a speed value that determines how fast to move it.
- The client uses remote functions to set the speed of the ship.
- Each client translates the model in render step, and the server translates in heartbeat.
However I have a very strange problem, the server is completely smooth but the client has some parts that are left behind, it almost seems like the network is syncing before TranslateBy is done moving all the parts.
Example
Server(Smooth)
Gif
Client(Some parts of the model are left behind until the next sync)
Gif
Note when I play the game in the studio(Play not Test) the client is very smooth.
Code
Client
RunService:BindToRenderStep("move", Enum.RenderPriority.First.Value, function (delta)
for i, ship in ipairs(localShips) do -- localShips contain the models
local dt = (delta * 1000) / 16
local tSpeed = ship.speed.Value / 60
ship:TranslateBy(ship.PrimaryPart.CFrame.lookVector * (tSpeed * dt))
end
end)
Server
RunService.Heartbeat:Connect(function (delta)
local dt = (delta * 1000) / 16
local tSpeed = ship.speed.Value / 60
ship:TranslateBy(ship.PrimaryPart.CFrame.lookVector * (tSpeed * dt))
end)
Note
- The parts are anchored.
- I can't use any physics(body movers, motor6d).
- I have tried to stick the loops into their own coroutines and calculate my own delta.
- All parts have the same parent(should not matter).
Question
Any idea on why this is happening?
Is there a better way to do this?

4 comments
Why are you moving the ship in both the client and server? Any changes made to the server will replicate to the client, so translating the ship in the server will also move it in all clients.
Because movement is choppy if I rely solely on the server (Server updates at 20Hz)
Give network ownership to the player piloting the ship
I can't, the model is anchored.