Why is Run service having a big delay?

Greetings fellow devs!
Recently I tried to create a custom top-down view camera. To archive this I used a part in which I set the camera’s position once every RunService.Heartbeat. However two errors occurred:

  1. When the player hits the direction key (w for example), the character starts to move but the camera follows after a few seconds.

  2. The part set to be the camera is moving in a weird chunky way, which gives the illusion of low frame rate and frame overlap (you can spot this on the character where you can see some pretty interesting behaviours of the eye which are not there if you play the video in slow-mo)

For this project I used two scripts: a server script which creates and positions the part in the correct place and a local script which sets the Camera’s CFrame to the part’s CFrame.

ServerScript:

local CameraFolder = workspace.Cameras
local Run = game:GetService("RunService")

game.Players.PlayerAdded:Connect(function(player)
	local NewPart = Instance.new("Part")
	NewPart.Parent = CameraFolder
	NewPart.Size = Vector3.new(1,1,1)
	NewPart.Anchored = true
	NewPart.Name = player.Name
	NewPart.CanCollide = false
	player.CharacterAdded:Connect(function(Character)
		local Root = Character:WaitForChild("HumanoidRootPart")
		local RootPosition = Root.Position
		Run.Heartbeat:Connect(function()
			NewPart.Position = Vector3.new(Root.Position.X, RootPosition.Y + 3, Root.Position.Z + 5)
			NewPart.Rotation = Vector3.new(-70,0,0)
		end)
	end)
end)

Local Script

local run = game:GetService("RunService")
local plr = game.Players.LocalPlayer
local CameraPart
local CameraFolder = workspace.Cameras
local camera = workspace.CurrentCamera

wait()

for i, v in pairs(CameraFolder:GetChildren()) do
	if v.Name == plr.Name then
		CameraPart = v
		break
	end
end

run.Heartbeat:Connect(function()
	camera.CameraType = Enum.CameraType.Scriptable
	camera.CFrame = CameraPart.CFrame
end)

Here is the video showing the delay:

1 Like

Use BindToRenderStep for any camera stuff

1 Like


Like this?

camera.CameraType = Enum.CameraType.Scriptable
run:BindToRenderStep("SomeName", Enum.RenderPriority.Camera.Value, function()
  -- Set camera CFrame here
end)
1 Like

After trying it it didn’t work as intended. There is still some delay and the frame overlap effect… :frowning:

The reason is because use Hearbeat (which doesn’t fire fast enough to simulate a smooth camera movement), so, you’ll have to use RenderStepped and not position the camera’s CFrame to a part, rather a CFrame that you set on the place.
Try:

repeat wait() until game:IsLoaded();
local players = game:GetService("Players");
local localPlayer = players.LocalPlayer;
local character = localPlayer.Character;
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart");
local runService = game:GetService("RunService");
local currentCamera = workspace.CurrentCamera;
local heightAboveCharacter = 9; -- // Change this to whatever you like
local offsetX, offsetZ = 2, 3; -- // Change these to whatever you like
currentCamera.CameraType = Enum.CameraType.Scriptable;

local function render_Step(dt)
	currentCamera.CFrame = CFrame.new(humanoidRootPart.CFrame.Position + Vector3.new(offsetX, heightAboveCharacter, offsetZ)) * CFrame.Angles(math.rad(-70), 0, 0);
end;


-- // Connecting the event
runService.RenderStepped:Connect(render_Step)

There is no delay (mine has 60 FPS), keep in mind people with low FPS would experience some delay, as RenderStepped fires each time a frame is fired.

3 Likes

There is always a delay between the server and the client when parts move.
I would recommend doing the entire camera system locally rather than initiate it through the server.

Currently you are changing the cframe of the camera locally by using a part’s position. But the part’s position is changed on the server, which has a delay when replicating to client.

1 Like

what happens in the client isn’t the same thing that happens in the server, the game needs to be replicated to all the clients, and each client can edit the replicated version with local scripts, but what happens in a local game does not replicate to the server again except for the character moves and remote functions and events, so you need to think that when you move your character your computer send this information to the server through internet, so it take some time , this is the lag and can ruin the experience for competitive games.

so in your game, the client character moves and tells the server (it take some time but you dont see any lag normally because you are moving your caracter in your local computer) and than the server moves the part to the position of the player (and send this information of your character position and this part position to all clients, and it also take some time for reach you computer again) and when this information reach your computer, a local script tells the camera to move to the part, while the information was travelling between computers, your player have already moved more, so thats why this effect happens.

you can fix it by making the camera follow a part that is being moved by a local script and not a server sided one

1 Like

just do

local run = game:GetService("RunService")
local plr = game.Players.LocalPlayer
local CameraPart
local CameraFolder = workspace.Cameras
local camera = workspace.CurrentCamera

wait()

for i, v in pairs(CameraFolder:GetChildren()) do
	if v.Name == plr.Name then
		CameraPart = v
		break
	end
end

run.Heartbeat:Connect(function()
	camera.CameraType = Enum.CameraType.Scriptable
	camera.CFrame:lerp(CameraPart.CFrame, 0.2)
end)
1 Like

Thanks for the explanation and the solution! Just one small thing. Sometimes the game doesn’t find the character with the game.Players.LocalPlayer.Character but needs to be: game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()

Thanks a lot!
Yolo

1 Like

No problem! Anytime.
And about the fact that the game doesn’t sometimes find the player, you are right.
Will prevent directly-referencing it further. :pray:

1 Like