Ways to move your parts with 0 lag. (List of good and bad methods)

Hi guys. Have you been wondering what’s the most efficient way to move parts with almost 0 lag? I have also been wondering the same thing, until today. I have a list that contains over 20+ movement methods for how to keep your game running smoothly.

Methods with collisions on.
  1. TweenService (Server). This method works well, but sadly not for parts in clumps. Using this method on my 1000 parts gave me a whopping 20 FPS. I heavily don’t recommend using this method unless you’re just really fond of it. (Server)

  2. TweenService (Client). This method is just like the server method but can somewhat endure a bit more. I still had an awful 30 FPS versus the maximum 60 FPS.

  3. RunService (Server and Heartbeat). This method is just like TweenService server-side and dropped my FPS down to 20.

  4. RunService (Client and Heartbeat). This method is just like TweenService client-side and dropped my FPS down to 30. However, after a few parts were out of view, it went up to 40 unlike TweenService on both sides.

  5. RunService (Client and RenderStepped). This one actually greatly disappointed me. Somehow this was worse compared to all of the other ones I’ve went through. My FPS dropped not to 30, not to 20, but nearly 10 FPS. Since it’s impossible to do it on the server, this method is definitely a bust and isn’t too great to use.

  6. RunService (Server and Stepped). The exact same as RunService RenderStepped.

  7. RunService (Client and Stepped). The exact same as RunService RenderStepped.

  8. For loop (Server) This dropped my FPS all the way down to 20 and was a little choppy.

  9. For loop (Client) This one was interesting. It was flowing smoothly at first, but there was clearly an FPS nosedive and some choppy points. It went from 40 FPS to 30 FPS.

  10. While true do loop (Server) This was very choppy. Like I’m not even kidding. The FPS went straight to 20 and the entire thing was so displeasing to look at. It’s like the for loop server-side, but way choppier.

  11. While true do loop (Client) The results greatly surprised me. I expected it to be just like the for loop server-side/client-side, but no. The results were actually good? The FPS only dropped to 50! I thought I actually found a really good method code-wise! And so far, I think that is the only somewhat good method code-wise. However, when I looked in the direction of the parts, it dropped to 19 FPS before going back up to 30.

  12. AlignPosition (Server) Despite the bricks being pretty choppy, I maintained my 60 FPS. I only dropped to 20 because of such a large part number being spawned at the same time. Occasionally, the FPS dropped to 50, but it wouldn’t stay that way for long. Even looking in the direction of the parts didn’t drop my FPS. This is a pretty good movement method; my only complaint is the speed. It’s very hard to adjust the speed of it, but then again, it’s not for constant velocity now, is it?

  13. AlignPosition (Client) This was actually the exact same as the server-side method.

  14. LinearVelocity (Server) For the loop velocity version of AlignPosition, I was a little disappointed. My FPS dropped to 30, but when I looked in the direction of the parts or attempted to make my character jump, my FPS would drop to a horrible 20 FPS. :frowning:

  15. LinearVelocity (Client) This was slightly better than the server-side. I kept my 60 FPS for the most part unless I looked in the direction of the parts. But even still, my FPS would only drop to 45, the least being 40. And it’d fix itself shortly after putting me back at 50 FPS. This is also a pretty solid way of moving parts.

  16. VectorForce (Server) This was pretty good and was just like AlignPosition. I kept my 60 FPS! I would say that jumping decreased it to 45, but I think that was just my computer. Other than that, a pretty good movement method. My only complaint is the speed. There is sadly no way to change the speed unless you change the force, and even still, you can’t make the numbers go too low or else your part won’t move at all. My only reason for not recommending this one is because the parts literally go at the speed of light if the force isn’t lowered. It was also a bit choppy too.

  17. VectorForce (Client) The same as server-side. It made my character move slower for some odd reason.

Methods with collisions off.
  1. While true do methods with CanCollide, CanQuery, and CanTouch set to off (Server). This was ever so slightly choppy. However, after a couple of seconds, my FPS was right back at 60 with no issues. Yeah, and keep in mind this for the server. So, if 1000+ parts are moving server-side with almost no issues? Yeah, that’s pretty good.

  2. While true do methods with CanCollide, CanQuery, and CanTouch set to off (Client). This was nearly flawless. My FPS only dropped to 55, and quickly went back up to almost or exactly 60 FPS. I’m honestly very surprised with this one. I expected the while true do methods to be terrible, but it’s not! I’m not sure how it is with CanTouch (I think this allows .Touched events to work) set to on, but that can be something for you to try! (I might actually update this one.) This method is heavily recommended by me for movement.

  3. For loop methods with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). Same as while true do with CanCollide, CanQuery, and CanTouch set to off server-wise.

  4. For loop methods with every part’s CanCollide, CanQuery, and CanTouch set to off (Client). Same as while true do with CanCollide, CanQuery, and CanTouch set to off client-wise.

  5. RunService methods with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). These methods were pretty good for the most part. My FPS remained at 50+ or 60.

  6. RunService methods with every part’s CanCollide, CanQuery, and CanTouch set to off (Client).
    Nearly flawless. Even RenderStepped almost gave me no issues. Occasionally the FPS dropped to 55, but that’s pretty good considering.

  7. AlignPosition with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). It was still pretty choppy, but it was somewhat okay over time. My FPS dropped to 19 once the bricks started stacking up, but it went back up to 30-ish.

  8. AlignPosition with every part’s CanCollide, CanQuery, and CanTouch set to off (Client). This one was ever so slightly choppy. But it fixed itself after a bit of time. My FPS remained around 55 until the bricks stopped moving. It then went back up to 60 FPS.

  9. LinearVelocity with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). Alright, so this one was “interesting” to say the least. It was like the server-side LinearVelocity test with collisions set to on. However, the FPS was a little bit better after some time. I thought the collisions being set to on was causing them to scatter across the universe, but they just do that anyway I guess. :person_shrugging:

  10. LinearVelocity with every part’s CanCollide, CanQuery, and CanTouch set to off (Client). Same as the client-side test from earlier, except with almost no FPS drops. The lowest FPS I got was 40-ish FPS when the parts spawned, and 55+ when the parts were stacking up. It’d be pretty solid if it weren’t for the parts scattering across the universe never to be seen again. :melting_face:

  11. VectorForce with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). This, once again, made my parts travel at the speed of light and they reached the “out of bounds” zone, so they got deleted automatically. I don’t recommend this one for simple fact of the speed needs to be changed sometimes, but at the same time you can’t change it because then the parts don’t move! This can be quite annoying to use. The movement was also choppy still.

  12. VectorForce with every part’s CanCollide, CanQuery, and CanTouch set to off (Client). Three words. Speed of light.

  13. TweenService with every part’s CanCollide, CanQuery, and CanTouch set to off (Server). Since everything else worked fine with these specific properties off, I had high hopes for this one! But, sadly for TweenService, this was literally the same as the server-side TweenService test with these properties set to on. I had 30-35 FPS. Yeah, just 10+ extra FPS. It’d be okay if the game were running on a maximum 30 FPS, but the maximum FPS is 60. So, I don’t recommend using TweenService at all on the server. But what about the client?

  14. TweenService with every part’s CanCollide, CanQuery, and CanTouch set to off (Client). Once again, I had 30 FPS. But it was getting progressively better. The maximum amount of FPS I had was 46. Yeah, just 10 extra FPS once again. TweenService isn’t the best method for moving parts sadly.

Methods with collisions on and welds.
  1. TweenService (WeldConstraint and Server). Alright. So, if you don’t know, a WeldConstraint is used for welding things together. This can be useful for making tall buildings and what not. The Part0 is assigned to the WeldConstraint’s parent, and the Part1 is assigned to the part that you want Part0 to be constrained to. I tried this on the server, and I actually only dropped down to 50 FPS, but soon after went back up to 60. That’s impressive for the server, so I was pretty impressed with this result. Please note that this only works if you move the part by CFrame. Else, it won’t work. At least, not to my knowledge.

  2. TweenService (WeldConstraint and Client). This ran very smoothly. I highly recommend this method. I maintained my 60 FPS. However, please note that this only works if you make the part move by CFrame! Else, it won’t work. At least, not to my knowledge.

  3. RunService (WeldConstraint, Server, and Heartbeat). This was pretty good. I dropped to 50 FPS, but it went back up to 60.

  4. RunService (WeldConstraint, Client, and Heartbeat). This was nearly flawless. I barely dropped in FPS at all. I maintained 60 FPS, which leads me to say that this is very efficient. We’re already off to a great start.

  5. RunService (WeldConstraint, Client, and RenderStepped). Same as RunService.Heartbeat client-side.

  6. RunService (WeldConstraint, Server, and Stepped). Same as RunService.Heartbeat server-side.

  7. RunService (WeldConstraint, Client, and Stepped). Same as RunService.RenderStepped client-side.

  8. While true do (WeldConstraint and Server). This was pretty much the same as RunService.Heartbeat server-side, but I think I noticed a couple extra drops. It wasn’t terrible of course, the least FPS I had from the drops was 54. Other than that? Pretty-pretty good.

  9. While true do (WeldConstraint and Client). I maintained my 60 FPS. The drops still happened, but this time the least FPS I had was 55. Still really good though.

  10. For loop (WeldConstraint and Server). Same as while true do server-side.

  11. For loop (WeldConstraint and Client). Same as while true do client-side.

  12. PrismaticConstraint (Server). This one was quite chaotic. My FPS struggled to stay at 30 and up and the parts were doing some weird ritual that involved movements. Despite that though, I did get a strange scorpion shaped abomination :joy:. I took a screenshot, but for some reason it didn’t save. :confused:

  13. PrismaticConstraint (Client). Same as the server-side test, just a little smoother though. I did manage to take another screenshot of what strange formation the parts made though. Tell me what it looks like to you, if anything lol.

Methods with collisions off and welds.
  1. TweenService (WeldConstraint and Server). Same as the server-side test with collisions on. I expected this honestly.

  2. TweenService (WeldConstraint and Client). Same as the client-side test with collisions off. Once again, I expected this.

  3. RunService (WeldConstraint, Heartbeat, and Server). Same as the server-side test with collisions on. No issues at all.

  4. RunService (WeldConstraint, Heartbeat, and Client). Same as the client-side test with collisions on. Ran very smoothly.

  5. RunService (WeldConstraint, RenderStepped, and Client). Same as the client-side test with collisions on. By the way, expect this for a good portion of the list.

  6. RunService (WeldConstraint, Stepped, and Server). Same as the server-side test with collisions on.

  7. RunService (WeldConstraint, Stepped, and Client). Same as the client-side test with collisions on.

  8. For loop (WeldConstraint and Server). Same as the server-side test with collisions on.

  9. For loop (WeldConstraint and Client). Same as the client-side test with collisions on.

  10. While true do loop (WeldConstraint and Server). Same as the server-side test with collisions on.

  11. While true do loop (WeldConstraint and Client). Same as the client-side test with collisions on.

Now we’ve finally completed the list! So, what does this all tally up to? What’s the best method for moving parts?

WeldConstraints. I’ve seen almost no flaw when using this method. WeldConstraints are amazing and they should almost always be used when dealing with large amounts of parts. I also strongly recommend spawning parts on the client-side. From what I’ve seen, the server can handle a lot of weight (parts), but it struggles to do so. The client can handle a lot of weight with little to no issue. Heck, I could probably spawn 10,000 parts and have no issue. I haven’t tested this yet obviously and I don’t want my studio to crash, but I’m pretty confident that the client-side method is super effective. WeldConstraints + Client-side = Almost 0 lag.

So, there you have it! The most efficient method for moving parts without lag! I really wasn’t expecting this to take so long, but it’s finally done. I hope the people that experience lag issues when it comes to moving parts will see this, as I think they will find it very helpful. If you have any further suggestions for me to try out, please reply to me and tell me what your suggestion is! I promise I will try it and will get back with you.

(Tip: I heavily recommend spawning huge clumps of parts on the client-side instead of the server. Not only do the parts spawn faster, but the FPS drop will be very little. I assume you won’t be spawning 1000 parts at the same time as I did, so this should be way more effective for you. Thank you for reading!)

I read the comments, so I have added code for you guys. If you want to suggest any ways to improve my code, please let me know!

Click this to see all of the code that I used.

TweenService (Server)

local Players = game.Players or game:GetService("Players")
local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local Time = 10

local function Tween(Parts)
	local Info = TweenInfo.new(Time, Enum.EasingStyle.Linear)
	local Goal = {}
	Goal.Position = Parts.Position-Vector3.new(0, 0, 500)
	local Tween = TweenService:Create(Parts, Info, Goal)
	Tween:Play()
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			for i, v in ipairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Tween(Parts)
				end
			end
		end
	end
end)

TweenService (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
-- local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local Time = 10

local function Tween(Parts)
	local Info = TweenInfo.new(Time, Enum.EasingStyle.Linear)
	local Goal = {}
	Goal.Position = Parts.Position-Vector3.new(0, 0, 500)
	local Tween = TweenService:Create(Parts, Info, Goal)
	Tween:Play()
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			for i, v in ipairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Tween(Parts)
				end
			end
		end
	end
end)

RunService (Server and Heartbeat)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

local MaxStuds = -10

local function Loop(Parts)
	RunService.Heartbeat:Connect(function(DT)
		local DeltaMovement = DT * MaxStuds
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, DeltaMovement))
   end)
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			Loop(ThousandParts)
		end
	end
end)

RunService (Client and Heartbeat)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

local MaxStuds = -10

local function Loop(Parts)
	RunService.Heartbeat:Connect(function(DT)
		local DeltaMovement = DT * MaxStuds
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, DeltaMovement))
   end)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			Loop(ThousandParts)
		end
	end
end)

RunService (Client and RenderStepped)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

local MaxStuds = -10

local function Loop(Parts)
	RunService.RenderStepped:Connect(function(DT)
		local DeltaMovement = DT * MaxStuds
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, DeltaMovement))
   end)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			Loop(ThousandParts)
		end
	end
end)

RunService (Server and Stepped)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

local MaxStuds = -10

local function Loop(Parts)
	RunService.Stepped:Connect(function(Time, DT)
		local DeltaMovement = DT * MaxStuds
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, DeltaMovement))
   end)
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			Loop(ThousandParts)
		end
	end
end)

RunService (Client and Stepped)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

local MaxStuds = -10

local function Loop(Parts)
	RunService.Stepped:Connect(function(Time, DT)
		local DeltaMovement = DT * MaxStuds
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, DeltaMovement))
   end)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			Loop(ThousandParts)
		end
	end
end)

For loop (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function Loop(Parts)
	for i = 1, math.huge do
		task.wait()
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, -2))
	end
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
            ThousandParts.Parent = game.Workspace
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Loop(Parts)
				end
			end
		end
	end
end)

For loop (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function Loop(Parts)
	for i = 1, math.huge do
		task.wait()
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, -2))
	end
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
            ThousandParts.Parent = game.Workspace
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Loop(Parts)
				end
			end
		end
	end
end)

While true do loop (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function Loop(Parts)
	while true do
		task.wait()
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, -2))
	end
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Loop(Parts)
				end
			end
		end
	end
end)

While true do loop (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function Loop(Parts)
	while true do
		task.wait()
		Parts:PivotTo(Parts.WorldPivot * CFrame.new(0, 0, -2))
	end
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			ThousandParts.Parent = game.Workspace
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					Loop(Parts)
				end
			end
		end
	end
end)

AlignPosition (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local AlignPosition = Instance.new("AlignPosition")
	AlignPosition.Parent = Parts
	AlignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	AlignPosition.Attachment0 = Attachment0
	AlignPosition.MaxForce = math.huge
	AlignPosition.Responsiveness = 1 -- For speed. You can change it.
	AlignPosition.Position = Parts.Position-Vector3.new(0, 0, 500)
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

AlignPosition (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local AlignPosition = Instance.new("AlignPosition")
	AlignPosition.Parent = Parts
	AlignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	AlignPosition.Attachment0 = Attachment0
	AlignPosition.MaxForce = math.huge
	AlignPosition.Responsiveness = 1 -- For speed. You can change it.
	AlignPosition.Position = Parts.Position-Vector3.new(0, 0, 500)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

LinearVelocity (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local LinearVelocity = Instance.new("LinearVelocity")
	LinearVelocity.Parent = Parts
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	LinearVelocity.Attachment0 = Attachment0
	LinearVelocity.MaxForce = math.huge
	LinearVelocity.VectorVelocity = Parts.Position-Vector3.new(1, 0, 0)
end

Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

LinearVelocity (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local LinearVelocity = Instance.new("LinearVelocity")
	LinearVelocity.Parent = Parts
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	LinearVelocity.Attachment0 = Attachment0
	LinearVelocity.MaxForce = math.huge
	LinearVelocity.VectorVelocity = Parts.Position-Vector3.new(1, 0, 0)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

VectorForce (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local VectorForce = Instance.new("VectorForce")
	VectorForce.Parent = Parts
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	VectorForce.Attachment0 = Attachment0
	VectorForce.Force = Vector3.new(750, 0, 0)
end


Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

VectorForce (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
local RunService = game:GetService("RunService")
--local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

local function CreateVelocity(Parts)
	local VectorForce = Instance.new("VectorForce")
	VectorForce.Parent = Parts
	local Attachment0 = Instance.new("Attachment")
	Attachment0.Name = "Attachment0"
	Attachment0.Parent = Parts
	VectorForce.Attachment0 = Attachment0
	VectorForce.Force = Vector3.new(750, 0, 0)
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			for i, v in pairs(ThousandParts:GetChildren()) do
				if v.ClassName == "Part" then
					local Parts = v
					CreateVelocity(Parts)
				end
			end
			ThousandParts.Parent = game.Workspace
		end
	end
end)

WeldConstraint (Server)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
--local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

--[[NOTE: YOU DO NOT HAVE TO USE TWEENSERVICE FOR THE WELDCONSTRAINT METHODS.
YOU CAN CHANGE IT TO WHATEVER FUNCTION/LOOP YOU WANT TO CHANGE IT TO!]]

local Time = 10

local function Tween(Parts)
	local Info = TweenInfo.new(Time, Enum.EasingStyle.Linear)
	local Goal = {}
	Goal.CFrame = CFrame.new(Parts.Position+Vector3.new(-500, 0, 0))
	local Tween = TweenService:Create(Parts, Info, Goal)
	Tween:Play()
end

local function CreateWelds(Obj, MainPart)
	local WeldConstraint = script.WeldConstraint:Clone()
	WeldConstraint.Parent = Obj
	WeldConstraint.Part0 = WeldConstraint.Parent
	WeldConstraint.Part1 = MainPart
end


Players.PlayerAdded:Connect(function(Player)
	local Character = game.Workspace:WaitForChild(Player.Name, 30)
	if Character ~= nil then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			local MainPart = ThousandParts.MainPart
			for i, v in ipairs(ThousandParts:GetChildren()) do
				if v.Name == "Part" then
					local Parts = v
					CreateWelds(Parts, MainPart)
				end
			end
			ThousandParts.Parent = game.Workspace
			Tween(MainPart)
		end
	end
end)

WeldConstraint (Client)

local Players = game.Players or game:GetService("Players")
local ReplicatedStorage = game.ReplicatedStorage or game:GetService("ReplicatedStorage")
local Client = Players.LocalPlayer
--local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

-- local MaxStuds = -10

--[[NOTE: YOU DO NOT HAVE TO USE TWEENSERVICE FOR THE WELDCONSTRAINT METHODS.
YOU CAN CHANGE IT TO WHATEVER FUNCTION/LOOP YOU WANT TO CHANGE IT TO!]]

local Time = 10

local function Tween(Parts)
	local Info = TweenInfo.new(Time, Enum.EasingStyle.Linear)
	local Goal = {}
	Goal.CFrame = CFrame.new(Parts.Position+Vector3.new(-500, 0, 0))
	local Tween = TweenService:Create(Parts, Info, Goal)
	Tween:Play()
end

local function CreateWelds(Obj, MainPart)
	local WeldConstraint = script.WeldConstraint:Clone()
	WeldConstraint.Parent = Obj
	WeldConstraint.Part0 = WeldConstraint.Parent
	WeldConstraint.Part1 = MainPart
end

game.Workspace.ChildAdded:Connect(function(Child)
	if Child.Name == Client.Name then
		task.wait(8)
		local ThousandParts = ReplicatedStorage:FindFirstChild("1000 Parts")
		if ThousandParts ~= nil then
			local MainPart = ThousandParts.MainPart
			for i, v in ipairs(ThousandParts:GetChildren()) do
				if v.Name == "Part" then
					local Parts = v
					CreateWelds(Parts, MainPart)
				end
			end
			ThousandParts.Parent = game.Workspace
			Tween(MainPart)
		end
	end
end)

By the way, the LocalScripts are under “StarterPlayerScripts” which can be found in “StarterPlayer”. The ServerScripts are under the “Workspace”.

THANKS SO MUCH FOR YOUR PATIENCE! I REALLY WISH I COULD’VE MADE THIS SHORTER, BUT I DON’T THINK THERE WAS ANY WAY. I HOPE THIS HELPED YOU AND I APPRECIATE YOU TAKING THE TIME TO READ THIS IF IT WASN’T TL;DR!

39 Likes

I don’t understand how you can compare RunService with for loops?

wouldn’t you need a for loop with run service to update every 1000 parts?
and then, how does a for loop work exactly, if you want the code to run every frame?

It would be nice if you gave more detail or code snippets
Also, you should definitly test BulkMoveTo()

6 Likes

I use wait(1/60)

Last time I tried using task.wait() it didn’t wait one frame, I find it rather strange

2 Likes

ummm, wait() basically waits for 2 frames
task.wait() will wait for one frame
(If you don’t put a number inside wait()/task.wait(), it will yeild for the smallest amount of time it can yeild for)

for benchmarking purposes, you should probably use RunService.Heartbeat:Wait() to be sure that it will wait for only 1 frame

If you used wait() instead of task.wait(), your results might be flawed as that means the parts aren’t updated every frame

2 Likes

When I tried using task.wait() it seemed to be slower, but anyway you’re right, after all I didn’t really need it as it was just to speed up something I was testing

So… the tldr is that the CanCollide, CanQuery and CanTouch properties, do in fact have major performance boosts on moving parts when they are turned off.

2 Likes

The resource is overall on good track. To further improve it, @Tomi1231 has a very good point. Script details are crucial to understand the differences.

I imagine each part having its own script causes unbearable lag.

For example, I used the following simple snippet on the server with unmodified anchored parts, and ran the play test at 60 FPS and no spikes at all.

Code
local parts = workspace.Parts:GetChildren()

local vectorStep = Vector3.new(0,.1,0)

while true do
	for _,part in parts do
		part.CFrame = part.CFrame + vectorStep
	end
	task.wait()
end

RunService.Heartbeat version performed just as smoothly.

Don’t be disapponted, this was completely expected. RenderStepped fires before screen drawing, so it drastically impacts the frame rate.

Additionally, it’s interesting how part properties can affect performance.

  • CanCollide to false disables all collisions and excludes them from engine calculations.
  • CanQuery excludes raycasting from calculations.
  • CanTouch excludes touch events from calculations.
  • Neon should be the simplest of all materials to render.
  • Shadows can have some impact.

The lowest wait() can go is 0.03 seconds (1/30) at best. It should more or less not be used anymore (article by EvaEra: https://eryn.io/gist/3db84579866c099cdd5bb2ff37947cec).

3 Likes

Hey guysss. I’m finally done lol. This took over two hours to complete. I hope you’re satisfied! (If you find any code bugs, please let me know.)

1 Like

You don’t need a for loop. RunService.Heartbeat automatically updates the parts without you needing a for loop according to every heartbeat.

1 Like

Yeah, use task.wait(). wait() is also deprecated.

1 Like

Oh, I didn’t realise that you were moving all the parts as a model, I thought you were moving them individually.

From my own testing, when it comes to moving a model, you want to unanchor all but 1 parts and weld all of the parts togheter. You can then change the CFrame of the anchored part (or use PivotTo on that part) and you should see better performance. Calling PivotTo() on the model, even all welded, is slower. This could also possibly be the reason why TweenService was so bad, as you are creating 1000 tweens (though PivotTo() still has to move all the parts individually I assume?). TweenService can actually be called on that anchored part and you can move those 1000 parts with a single tween.

You can even use BulkMoveTo() to move multiple models at the same time by putting in the anchored parts of the models

for i = 1, math.huge do end feels so wrong lol

5 Likes

Thanks for that suggestion. I’ll be trying that and adding it to the list! (Believe it or not, I actually used to do this a lot, but I figured it wasn’t efficient. Shame on me huh? :melting_face:)

1 Like

Yes. I have no idea how “CanTouch” performs being switched to on though. I was pretty shocked at the results too honestly.

1 Like

I actually did move the parts as a model and not using a ton of scripts, as that would cause lag and far too much work. I suppose I could clone them, but I wouldn’t have time to do that.

2 Likes

What about a PrismaticConstraint with a main Brick while the others are welded to it?

1 Like

Hey there! Updated the post. Check the constraint part for new information. Scripts have not been posted yet.

2 Likes

Hey, I updated the post. Check the constraint part to see new information. Constraint scripts have not been posted yet, as I’m quite tired from all of this and need a break. Could you also tell me how to use “BulkMoveTo()”? I tried to use it on multiple occasions, but it never appeared as anything valid.

1 Like

To use BulkMoveTo() you need two arrays. The first array contains the instances you want to move (BaseParts), so if you have a model made with weld, that would be the anchored part in the model.
The second table is the CFrame table. How it works is that the first part in the instance table will be moved to the first CFrame in the CFrame table, same for the second, third etc. Both tables need to be the same lenght

Here, I insert the instance and the CFrame into two tables
image

Then here, BulkMoveTo() is used


The last parameter is optional and I think it is FireCFrameChanged by default, but basically what it does is prevent it from firing the PositionChanged and OrientationChanged which helps for performance

The tables are then cleared for the next frame, if you make new tables every time, this is not needed (but keeping the same tables is a good idea)

3 Likes

The while true do method of moving parts has the problem that it’s speed is determined by framerate. Altough this can easily be fixed by using delta time.

local parts = workspace.Parts:GetChildren()

local vectorStep = Vector3.yAxis * 6

game:GetService("RunService").Heartbeat:Connect(function(delta)
	for _,part in parts do
		part.CFrame *= CFrame.new(vectorStep * delta)
	end
	task.wait()
end)
1 Like

This is confusing. How can something that determines if something is running on client or server be compared with a service that has a connection that runs every frame?

It literally is tho.

1 Like