Player stuttering with CFrame?

So I’ve got this script below which updates the players CFrame while the model is moving but when other players see different players, they appear to be stuttering like this -

script-

while true do

	local Players = game:GetService("Players")
	local player = game.Players.LocalPlayer
	local RunService = game:GetService('RunService')

	local LastHit
	local LastTrainCFrame

	local Function
	local Function2


	local Whitelist = {workspace:WaitForChild('Map1', 20)}
	
	
	Function = RunService.Heartbeat:Connect(function()
		local RootPart = player.Character.HumanoidRootPart
		local Ignore = player.Character
		local ray = Ray.new(RootPart.CFrame.p, Vector3.new(0,-200,0))
		local Hit, Position, Normal, Material
		if LastHit then
			Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,{LastHit})
			if not Hit then
				Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
			end
		else
			Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
		end
		if Hit then
			local Train = Hit
			if not LastTrainCFrame then
				LastTrainCFrame = Train.CFrame
			end
			local TrainCF
			if Train ~= LastHit and LastHit then
				TrainCF = LastHit.CFrame
			else
				TrainCF = Train.CFrame
			end
			local Rel = TrainCF * LastTrainCFrame:inverse()
			LastTrainCFrame = Train.CFrame
			RootPart.CFrame = Rel * RootPart.CFrame
			LastHit = Train
			if Train ~= LastHit then
				LastTrainCFrame = Train.CFrame
			end
		else
			LastTrainCFrame = nil
		end
		

		if not Function2 then
			Function2 = player.Character.Humanoid.Died:Connect(function()
				Function:Disconnect()
				Function2:Disconnect()

			end)
		end
	end)
	wait(140)
end
1 Like

what do you mean exactly by update a player’s CFrame?

1 Like

Video is a wmv file, nobody can see it and nobody is gonna download it. Try making it .mp4 or another acceptable file type if you wanna get more people to help.

1 Like

I mean that the player moves along with the model when the model starts moving.

1 Like

Right I have now fixed the video

1 Like

does it look different when the client is looking at itself? Also i’m pretty sure characters would automatically move with the model if it moved

1 Like

Well when the player sees themselves when they see their own character, it’s not stuttering. When that player is looking at a different player on their screen, they stutter, as you can see in the video.

1 Like

Does anybody have any possible solutions?

1 Like

You might want to consider doing this server-side, because the stuttering on other clients may be to do with replication lag.

1 Like

how would I go about doing that? I don’t have a clue. Do I have to change code for server script and if so, what?

1 Like

Run the code on the server (normal script, not localscript), but instead of getting the player from LocalPlayer, try getting it from running an ipairs loop over the table returned Players:GetPlayers() to do it for every player server-side instead of on each individual client. It should still work from what I can tell, but you might have to change some things.

well I’ve tried so far but I’m getting multiple errors

while true do

	local Players = game:GetService("Players")
	local RunService = game:GetService('RunService')
	local LastHit
	local LastTrainCFrame

	local Function
	local Function2


	local Whitelist = {workspace:WaitForChild('Map1', 20)}
	
	wait(2)
	
	for _,v in ipairs(game.Players:GetPlayers()) do

		Function = RunService.Heartbeat:Connect(function()

		local RootPart = game.Players.Character.HumanoidRootPart - **This line errors with    Character is not a valid member of Players "Players"**

		local Ignore = game.Players.Character

		local ray = Ray.new(RootPart.CFrame.p, Vector3.new(0,-200,0)) - **This line also tends to error with CFrame is not a valid member of p.**

		local Hit, Position, Normal, Material
		if LastHit then
			Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,{LastHit})
			if not Hit then
			Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
			end
		else
			Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
		end
		if Hit then
			local Train = Hit
			if not LastTrainCFrame then
				LastTrainCFrame = Train.CFrame
			end
			local TrainCF
			if Train ~= LastHit and LastHit then
				TrainCF = LastHit.CFrame
			else
				TrainCF = Train.CFrame
			end
			local Rel = TrainCF * LastTrainCFrame:inverse()
			LastTrainCFrame = Train.CFrame
			RootPart.CFrame = Rel * RootPart.CFrame
			LastHit = Train
			if Train ~= LastHit then
				LastTrainCFrame = Train.CFrame
			end
		else
			LastTrainCFrame = nil
		end


		if not Function2 then
			Function2 = game.Players.Character.Humanoid.Died:Connect(function()
				Function:Disconnect()
				Function2:Disconnect()

			end)
		end
	end)
	wait(140)
	end
	end

Instead of using ‘game.Players.Character’ etc., use v.Character, as v is the player in the loop. If you get any more errors after that, screenshot/copy them into here.

right I’ve made the changes but now the whole map stutters and the player can’t move around on the model. I’m not getting any errors though in console. Video of that -

New code -

while true do

	local Players = game:GetService("Players")
	local RunService = game:GetService('RunService')
	local LastHit
	local LastTrainCFrame

	local Function
	local Function2


	local Whitelist = {workspace:WaitForChild('Map1', 20)}

	wait(2)

	for _,v in ipairs(game.Players:GetPlayers()) do

		Function = RunService.Heartbeat:Connect(function()

			local RootPart = v.Character.HumanoidRootPart 

			local ignore = v.Character

			local ray = Ray.new(RootPart.CFrame.p, Vector3.new(0,-200,0)) 

				local Hit, Position, Normal, Material
			if LastHit then
				Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,{LastHit})
				if not Hit then
					Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
				end
			else
				Hit, Position, Normal, Material = workspace:FindPartOnRayWithWhitelist(ray,Whitelist)
			end
			if Hit then
				local Train = Hit
				if not LastTrainCFrame then
					LastTrainCFrame = Train.CFrame
				end
				local TrainCF
				if Train ~= LastHit and LastHit then
					TrainCF = LastHit.CFrame
				else
					TrainCF = Train.CFrame
				end
				local Rel = TrainCF * LastTrainCFrame:inverse()
				LastTrainCFrame = Train.CFrame
				RootPart.CFrame = Rel * RootPart.CFrame
				LastHit = Train
				if Train ~= LastHit then
					LastTrainCFrame = Train.CFrame
				end
			else
				LastTrainCFrame = nil
			end


			if not Function2 then
				Function2 = v.Character.Humanoid.Died:Connect(function()
					Function:Disconnect()
					Function2:Disconnect()

				end)
			end
		end)
		wait(140)
	end
end


Are you trying to move a character with an object? Because instead of using CFrame to move both just use a BodyPosition to do that. Also I believe the stutter is just how roblox work and there is no real easy way to fix it.

yeah i am trying to move the player with the model. It worked fine as a local script, but only if that player was only watching themselves. If they saw another player, they would be stuttering.

Is there any reason to wrap the whole file in a while loop. You are creating connections every 140 seconds which do the same thing which may be a reason why it stutters?

Another thing I noticed was that your math for calculating the offset is wrong.
You are currently doing …

CurrentCFrame * lastCFrame:inverse()

This is wrong, we can prove it by deriving it the correct way

lastCFrame * offset = CurrentCFrmae
lastCFrame:inverse() * lastCFrame * offset = lastCFrame:inverse() * CurrentCFrame
offset = lastCFrame:inverse() * CurrentCFrame

Well i thought i needed to do that so that when a new map would spawn in from server storage, this script would be already running for the players when they teleport to the new map, so that they can move with the model. That’s why I’ve got 140 second wait because that’s the length of time per round.

Well those connections are never being cleaned up. IE you have created a memory leak as the only reference to that connection exists inside the scope of the while loop during its current iteration. After the while loop goes to its next iteration, you will lose reference to the connection you have made which you have stored inside the local variable Function.

Could it even be more efficient to just put a BodyVelocity on the characters that matches the train’s velocity? (Especially if the train itself uses one)