I have a server-sided script that changes the direction of a moving ball. However, the inputs feel quite delayed and not very instantaneous. I’ve tried a few solutions like setting the network owner of the ball to the player, and trying to make the application of the force instantaneous and at max power. In my debugging process, I measured the client-server delay and it averages 0.09 seconds (at least I think it’s seconds, let me know)
Here is the game link if anyone wants to try: SLANT - Roblox
Game works 100% fine in studio but is very laggy in game.
Server side snippet (handles the application of the force from the client)
RunService.Heartbeat:Connect(function(dt)
for _, player in ipairs(Players:GetPlayers()) do
local direction = playerDirections[player]
if not direction then playerDirections[player] = 0 end
local character = player.Character
if not character then print("No char") continue end
local ball = character:FindFirstChild("Ball")
local attachment = ball and ball:FindFirstChild("Attachment")
local vectorForce = ball and ball:FindFirstChild("VectorForce")
if not (ball and attachment and vectorForce) then continue end
setupBallCollision(player,ball)
-- Apply proportional force to close the gap
--local forwardSpeedRatio = math.min(math.abs(forwardSpeed) / maxSpeed, 1)
--local dynamicForwardForce = math.clamp(forwardForce * (1 - forwardSpeedRatio), 0, forwardForce)
local localVelocity = ball.CFrame:VectorToObjectSpace(ball.AssemblyLinearVelocity)
local lateralSpeed = localVelocity.X
local forwardSpeed = localVelocity.Z
local speedMultiplier = playerSpeedMultipliers[player] or 1
local desiredSideSpeed = direction * maxSideSpeed
local sideSpeedDiff = desiredSideSpeed - lateralSpeed
local adjustedSideForce = sideSpeedDiff * maxSideSpeed
local forwardSpeedDiff = (maxSpeed * speedMultiplier) - forwardSpeed
local dynamicForwardForce = math.clamp(forwardSpeedDiff * 50, 0, forwardForce * speedMultiplier)
local totalForce = Vector3.new(adjustedSideForce, 0, dynamicForwardForce)
vectorForce.Force = totalForce
end
end)
-- Update movement direction from clients
BallControlEvent.OnServerEvent:Connect(function(player, direction)
if typeof(direction) == "number" then
print("Moving "..tostring(direction))
playerDirections[player] = direction
BallControlEvent:FireClient(player)
else
warn("Invalid direction from", player.Name)
end
end)
-- Cleanup
Players.PlayerRemoving:Connect(function(player)
playerDirections[player] = nil
end)
Client side (Gets the movedirection from inputs and fires an event to the server)
-- Send direction to server if changed
local function updateDirection(newDirection)
if moveDirection ~= newDirection then
moveDirection = newDirection
print("Inputted "..tostring(newDirection))
BallControlEvent:FireServer(moveDirection)
end
end
--When the server lets the client know that it receieved the call
BallControlEvent.OnClientEvent:Connect(function()
plr.PlayerGui.GameGui.server.Visible = true
wait(1)
plr.PlayerGui.GameGui.server.Visible = false
end)
-- Keyboard input and showing the client-server delay
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.Left then
updateDirection(1)
local dlay = 0
plr.PlayerGui.GameGui.client.Visible = true
repeat dlay+=task.wait() until plr.PlayerGui.GameGui.server.Visible == true
dlay = math.floor(dlay*1000)
dlay = dlay / 1000
plr.PlayerGui.GameGui.delay.Text = "Delay: "..tostring(dlay)
plr.PlayerGui.GameGui.client.Visible = false
elseif input.KeyCode == Enum.KeyCode.D or input.KeyCode == Enum.KeyCode.Right then
updateDirection(-1)
local dlay = 0
plr.PlayerGui.GameGui.client.Visible = true
repeat dlay+=task.wait() until plr.PlayerGui.GameGui.server.Visible == true
dlay = math.floor(dlay*1000)
dlay = dlay / 1000
plr.PlayerGui.GameGui.delay.Text = "Delay: "..tostring(dlay)
plr.PlayerGui.GameGui.client.Visible = false
end
end)
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.Left or
input.KeyCode == Enum.KeyCode.D or input.KeyCode == Enum.KeyCode.Right then
updateDirection(0)
if UserInputService:IsKeyDown(Enum.KeyCode.A) or UserInputService:IsKeyDown(Enum.KeyCode.Left) then
updateDirection(1)
end
if UserInputService:IsKeyDown(Enum.KeyCode.D) or UserInputService:IsKeyDown(Enum.KeyCode.Right) then
updateDirection(-1)
end
end
end)
let me know if you need the full scripts.