How to fix lag in Custom Character Movement?

Hello, I’m trying to create a Custom Movement for a Dragon ball game that supports fusions,
this modified move makes players who are inside the fusion able to control the same character at the same time,
the system works but the only problem is lag when moving.

the Custom Movement has a little delay, but for a fighting game, this is bad.

and that lag doesn’t happen in the studio.

the video:
robloxapp-20221011-1417210.wmv (2.5 MB)

the system works in local script:

function Play()

	local Player = LocalPlayer

	local Pos = Player.Character:WaitForChild('MoveDirection').Value

	local Run = false

	local Jump = false

	local Stop = false
	
	--This is for the character not to move when is anchored
	for i,v in pairs(Player.Character:GetChildren()) do
		if v:IsA("BasePart") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
			if v.Anchored == true then
				Stop = true
			end
		end
	end

	local JumpPower = 50

	if Player.Character:FindFirstChild('ValueRun') ~= nil then
		if Player.Character:FindFirstChild('ValueRun').Value == true then
			Run = true
		end
	end

	if Player.Character:FindFirstChild('ValueJump') ~= nil then
		if Player.Character:FindFirstChild('ValueJump').Value == true then
			Jump = true
		end
	end
	
	if #game.Players:GetPlayers() > 1 then
		
		--This is for someone in the fusion to control
		pcall(function()

			local PlayersFusion = 0

			for _,players in pairs(game.Players:GetPlayers()) do
				if players.Name ~= Player.Name then
					if players.Character ~= nil then
						if players.Character:FindFirstChild("MoveDirection") ~= nil then
							if players.Character:FindFirstChild("PlayerFusion") ~= nil then
								if players.Character:FindFirstChild("PlayerFusion").Value == Player.Name then

									PlayersFusion = PlayersFusion +1

									if table.find(TablePlayersFusion,players.Name) then

									else
										table.insert(TablePlayersFusion,players.Name)
										game.ReplicatedStorage:WaitForChild("Event"):WaitForChild("LoadCharacter"):FireServer(players)
									end

									if workspace:WaitForChild("PlayerDead"):FindFirstChild(players.Name) ~= nil then
										print("Dead: " .. players.Name .. "Fusion: " .. Player.Name)
										DiedPlayerFusion = true
										game.ReplicatedStorage:WaitForChild("Event"):WaitForChild("DeadFusion"):FireServer(players.Name)
									end

									if players.Character:FindFirstChild("PlayerFusion"):FindFirstChild("ValuePlay") ~= nil then
										if players.Character:FindFirstChild("PlayerFusion"):FindFirstChild("ValuePlay").Value == true then

											Pos += players.Character:FindFirstChild("MoveDirection").Value

											if Run == false then
												if players.Character:FindFirstChild('ValueRun') ~= nil then
													if players.Character:FindFirstChild('ValueRun').Value == true then
														Run = true
													end
												end
											end

											if Jump == false then
												if players.Character:FindFirstChild('ValueJumpServer') ~= nil then
													if players.Character:FindFirstChild('ValueJumpServer').Value == true then
														Jump = true
													end
												end
											end

										end
									end

								end
							end
						end
					end
				end
			end

			--if PlayersFusion <= 1 then
			--	if PlayTestFusion == true and DiedPlayerFusion == true then
			--		PlayTestFusion = false

			--		game.ReplicatedStorage:WaitForChild("Event"):WaitForChild("DeadCharacter"):FireServer()

			--	end
			--end

		end)
		
	end
	
	if Pos == nil or Stop == true then
		Pos = Vector3.new(0,0,0)
		Run = false
		Jump = false
	end

	if Pos.X > 1 then
		Pos = Vector3.new(1,Pos.Y,Pos.Z)
	end
	if Pos.Y > 1 then
		Pos = Vector3.new(Pos.X,1,Pos.Z)
	end
	if Pos.Z > 1 then
		Pos = Vector3.new(Pos.X,Pos.Y,1)
	end
	
	--This is for animation to work
	if Pos.X > 0.3 or Pos.Z > 0.3 or Pos.X < -0.3 or Pos.Z < -0.3 then
		if AnimPlay.IsPlaying == false then
			AnimPlay:Play()
		end
	else
		if AnimPlay.IsPlaying == true then
			AnimPlay:Stop()
		end
	end
	
	--This is for the character to look in the direction he is walking
	local PosBodyGyro = HR.CFrame.Position + Pos

	BodyGyro.CFrame = CFrame.new(HR.CFrame.Position, Vector3.new(0,1,0)+PosBodyGyro)

	Pos = Pos / 3.5
	
	--This here is to adjust the speed of the player
	if Player.Character:FindFirstChild("Values") ~= nil then
		if Player.Character:FindFirstChild("Values"):FindFirstChild("WalkSpeed") ~= nil then
			Pos = Pos * (Player.Character:FindFirstChild("Values"):FindFirstChild("WalkSpeed").Value / 16)
		end
	end
	
	--This here is to adjust the player's jump power
	if Player.Character:FindFirstChild("Values") ~= nil then
		if Player.Character:FindFirstChild("Values"):FindFirstChild("JumpPower") ~= nil then
			JumpPower = JumpPower * (Player.Character:FindFirstChild("Values"):FindFirstChild("JumpPower").Value / 50)
		end
	end

	if Run == true then
		Pos = Pos * 1.5
	end
	
	--This is for the character to jump
	if Jump == true then
		if AnimPlayJump.IsPlaying == false then
			AnimPlayJump:Play()
		end
		BodyVelocity.Velocity = Vector3.new(0,JumpPower,0)
		BodyVelocity.MaxForce = Vector3.new(0,math.huge,0)
	else
		BodyVelocity.Velocity = Vector3.new(0,0,0)
		BodyVelocity.MaxForce = Vector3.new(0,0,0)
		if AnimPlayJump.IsPlaying == true then
			AnimPlayJump:Stop()
		end
	end

	local PosPlayer = Player.Character:WaitForChild('HumanoidRootPart').CFrame

	local CFrameValue = PosPlayer + Pos
	
	--local PosBodyVelocity = Pos * 3.5 * 16
	
	--BodyVelocity.MaxForce = Vector3.new(math.huge,BodyVelocity.MaxForce.Y,math.huge)
	--BodyVelocity.Velocity = Vector3.new(PosBodyVelocity.X,BodyVelocity.Velocity.Y,PosBodyVelocity.Z)

	Player.Character:SetPrimaryPartCFrame(CFrameValue)

end

--while wait() do
--	Play()
--end

if game:GetService("RunService"):IsClient() then

	print("Custom Character Movement Loading by: Client")

	game:GetService("RunService").RenderStepped:Connect(function()
		Play()
	end)
elseif game:GetService("RunService"):IsServer() then
	
	--this here is because I tested it on the server but it didn't work
	
	print("Custom Character Movement Loading by: Server")

	game:GetService("RunService").Stepped:Connect(function()
		Play()
	end)
end

I tried using Heartbeat, but it didn’t make much difference and I ended up leaving the player lagging

Can anyone help me to optimize this local script?

I noticed that this part of your code grabs all the players in the server

for _,players in pairs(game.Players:GetPlayers()) do

Do this is really needed?, If a lot of players are in the server this going to be real slow.

Note that the code won’t run in the server because there are no players (I think).

I’ve already disabled this for testing

but it didn’t make much difference

but I will try to modify

But what can I do for the script to know which player is in the fusion.

I will make this code separate from the script.

Thanks. the game is now with less lag.

Do it? Wow, I don’t expect that really troubleshoot it! Was nothing, and you can index the players in a table to fusion those.

Good afternoon, body.

I just separated the script codes. Now it doesn’t even feel like it has lag. and had other scripts that used for i,v in pairs do

And I put a wait() to not give lag.

Custom Character Movement couldn’t use wait() so it’s better to separate.