[Free code] Fast rope code. No lag

So I wanted to make some decorative rope that’s really fast. I wanted to be able to run as many ropes as I wanted to at the same time. So I made this.
160 strands of rope running at 60 frames per second.

Click for MP4 version: http://i.gyazo.com/97d26b339245401ca4e6db6fe56de8f9.mp4
For a live demo, go here: FastRope (Press F9) - Roblox

You’ll see how it’s able to do this when you look at the code.

It uses 0 tables, other than when returning mutator functions. It uses no vector3 or CFrame library unless it’s needed or faster to do so with it. All of the code is expended as much as possible to be as fast as possible. It takes up so much memory, but that doesn’t matter because memory grows on trees and therefor even if you made a thousand ropes, you wouldn’t run out of memory.

The code, with an example, is provided below.

--[[
Documentation


Read and Write Properties:
.Length Number
	Length in studs of the Rope

.Thickness Number
	Thickness in studs of the Rope

.Material String
	Part Material of the Rope

.Transparency Number
	Part Transparency of the Rope

.Reflectance Number
	Part Reflectance of the Rope

.Parent Userdata
	Parent of the Rope

.FrontPosition Vector3
	The Position of the front end of the Rope

.EndPosition Vector3
	The Position of the end end of the Rope

.FrontAnchored Bool
	Whether the front end is anchored
	
.EndAnchored Bool
	Whether the end end is anchored

.FrontAttach Userdata Part
	The Part that the front end of the Rope is attached too

.EndAttach Userdata Part
	The Part that the end end of the Rope is attached too

.FrontOffset Vector3
	The offset applied relative to FrontAttach

.EndOffset Vector3
	The offset applied relative to EndAttach


Methods:
:Remove()
	Removes the Rope --I probably need to fix this to work completely.

:PositionAtLength(Length)
	Returns the Position on the Rope at the length from the front
]]

local Rope={}
do
	local cf=CFrame.new
	local v3=Vector3.new
	local RenderStepped=game:GetService("RunService").RenderStepped
	local garbagecollect=garbagecollect
	local setmetatable=setmetatable

	function Rope.New(Parent)
		--[[Naming convention:
			CurrentPosition XElementOfVector Point0		cx0
			LastPosition YElementOfVector Point4		ly4
			
			<cx0,cy,cz0> is the vector of the current position of the
			zeroth point of the string.
			<lx0,ly0,lz0> is the vector of the last position of the
			zeroth point of the string.
			
			r2 is the (target radius between points)^2

			Attach8 is the Part Point8 is attached to
			Offset0 is the offset that is applied to the CFrame of the Attach0 Part.
			
			Part1 is the part which connectes Point0 and Point1
			Mesh5 is the mesh which defines the size of Part5

			The rest is self explanatory
		]]
		local Length=8
		local Thickness=1
		local Material="Plastic"
		local Transparency=0
		local Reflectance=0
		local BrickColor=BrickColor.new("Medium grey")

		local r2=1
		local Attach0,Attach8
		local Offset0,Offset8=v3(),v3()
		local Anchored0,Anchored8=true,false
		local Model=Instance.new("Model",Parent or game.Workspace)

		local cx0,cy0,cz0=0,0,0
		local lx0,ly0,lz0=0,0,0

		local cx1,cy1,cz1=1,0,0.1
		local lx1,ly1,lz1=1,0,0.1

		local cx2,cy2,cz2=2,-0.1,0
		local lx2,ly2,lz2=2,-0.1,0

		local cx3,cy3,cz3=3,0,-0.1
		local lx3,ly3,lz3=3,0,-0.1

		local cx4,cy4,cz4=4,0.1,0
		local lx4,ly4,lz4=4,0.1,0

		local cx5,cy5,cz5=5,0,0.1
		local lx5,ly5,lz5=5,0,0.1

		local cx6,cy6,cz6=6,-0.1,0
		local lx6,ly6,lz6=6,-0.1,0

		local cx7,cy7,cz7=7,0,-0.1
		local lx7,ly7,lz7=7,0,-0.1

		local cx8,cy8,cz8=8,0,0
		local lx8,ly8,lz8=8,0,0

		local Ball0=Instance.new("Part",Model)
		local BallMesh0=Instance.new("SpecialMesh",Ball0)
		Ball0.Anchored=true
		Ball0.CanCollide=false
		Ball0.FormFactor="Custom"
		Ball0.Size=v3(0.2,0.2,0.2)
		BallMesh0.MeshType="Sphere"

		local Part1=Instance.new("Part",Model)
		local Mesh1=Instance.new("CylinderMesh",Part1)
		Part1.Anchored=true
		Part1.CanCollide=false
		Part1.FormFactor="Custom"
		Part1.Size=v3(0.2,0.2,0.2)

		local Ballo=Ball0:Clone()

		local Part2=Part1:Clone()
		local Mesh2=Instance.new("CylinderMesh",Part2)
		Part2.Parent=Model

		local Ball2=Ball0:Clone()

		local Part3=Part1:Clone()
		local Mesh3=Instance.new("CylinderMesh",Part3)
		Part3.Parent=Model

		local Ball3=Ball0:Clone()

		local Part4=Part1:Clone()
		local Mesh4=Instance.new("CylinderMesh",Part4)
		Part4.Parent=Model

		local Ball4=Ball0:Clone()

		local Part5=Part1:Clone()
		local Mesh5=Instance.new("CylinderMesh",Part5)
		Part5.Parent=Model

		local Ball5=Ball0:Clone()

		local Part6=Part1:Clone()
		local Mesh6=Instance.new("CylinderMesh",Part6)
		Part6.Parent=Model

		local Ball6=Ball0:Clone()

		local Part7=Part1:Clone()
		local Mesh7=Instance.new("CylinderMesh",Part7)
		Part7.Parent=Model

		local Ball7=Ball0:Clone()

		local Part8=Part1:Clone()
		local Mesh8=Instance.new("CylinderMesh",Part8)
		Part8.Parent=Model

		local Ball8=Ball0:Clone()


		local function AttachUpdate()
			if Attach0 then
				local p=Attach0.CFrame*Offset0
				cx0,cy0,cz0=p.x,p.y,p.z
			end
			if Attach8 then
				local p=Attach8.CFrame*Offset8
				cx8,cy8,cz8=p.x,p.y,p.z
			end
		end


		local function PhysicsUpdate()
			local rx,ry,rz,lr,m,mx,my,mz--Relative x,y,z, l^2 over r^2 - 1, m is.. eh.
			if not Anchored0 then
				cx0,lx0=cx0*2-lx0,cx0
				cy0,ly0=cy0*2-ly0,cy0+0.0545--0.0545 is for ROBLOX gravity. 9.81*20/60^2
				cz0,lz0=cz0*2-lz0,cz0
			end

			cx1,lx1=cx1*2-lx1,cx1
			cy1,ly1=cy1*2-ly1,cy1+0.0545
			cz1,lz1=cz1*2-lz1,cz1

			cx2,lx2=cx2*2-lx2,cx2
			cy2,ly2=cy2*2-ly2,cy2+0.0545
			cz2,lz2=cz2*2-lz2,cz2

			cx3,lx3=cx3*2-lx3,cx3
			cy3,ly3=cy3*2-ly3,cy3+0.0545
			cz3,lz3=cz3*2-lz3,cz3

			cx4,lx4=cx4*2-lx4,cx4
			cy4,ly4=cy4*2-ly4,cy4+0.0545
			cz4,lz4=cz4*2-lz4,cz4

			cx5,lx5=cx5*2-lx5,cx5
			cy5,ly5=cy5*2-ly5,cy5+0.0545
			cz5,lz5=cz5*2-lz5,cz5

			cx6,lx6=cx6*2-lx6,cx6
			cy6,ly6=cy6*2-ly6,cy6+0.0545
			cz6,lz6=cz6*2-lz6,cz6

			cx7,lx7=cx7*2-lx7,cx7
			cy7,ly7=cy7*2-ly7,cy7+0.0545
			cz7,lz7=cz7*2-lz7,cz7

			if not Anchored8 then
				cx8,lx8=cx8*2-lx8,cx8
				cy8,ly8=cy8*2-ly8,cy8+0.0545
				cz8,lz8=cz8*2-lz8,cz8
			end
			--local asd=tick()
			for i=1,32 do
				local avg=0
				rx,ry,rz=cx1-cx0,cy1-cy0,cz1-cz0
				if Anchored0 then
					lr=(rx*rx+ry*ry+rz*rz)/r2-1
					avg,m=avg+lr*lr,lr/(lr*2+2)
					cx1,cy1,cz1=cx1-rx*m,cy1-ry*m,cz1-rz*m
				else
					lr=(rx*rx+ry*ry+rz*rz)/r2-1
					avg,m=avg+lr*lr,lr/(lr*4+4)
					mx,my,mz=rx*m,ry*m,rz*m
					cx0,cy0,cz0=cx0+mx,cy0+my,cz0+mz
					cx1,cy1,cz1=cx1-mx,cy1-my,cz1-mz
				end

				rx,ry,rz=cx3-cx2,cy3-cy2,cz3-cz2
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx2,cy2,cz2=cx2+mx,cy2+my,cz2+mz
				cx3,cy3,cz3=cx3-mx,cy3-my,cz3-mz

				rx,ry,rz=cx5-cx4,cy5-cy4,cz5-cz4
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx4,cy4,cz4=cx4+mx,cy4+my,cz4+mz
				cx5,cy5,cz5=cx5-mx,cy5-my,cz5-mz

				rx,ry,rz=cx7-cx6,cy7-cy6,cz7-cz6
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx6,cy6,cz6=cx6+mx,cy6+my,cz6+mz
				cx7,cy7,cz7=cx7-mx,cy7-my,cz7-mz

				rx,ry,rz=cx2-cx1,cy2-cy1,cz2-cz1
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx1,cy1,cz1=cx1+mx,cy1+my,cz1+mz
				cx2,cy2,cz2=cx2-mx,cy2-my,cz2-mz

				rx,ry,rz=cx4-cx3,cy4-cy3,cz4-cz3
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx3,cy3,cz3=cx3+mx,cy3+my,cz3+mz
				cx4,cy4,cz4=cx4-mx,cy4-my,cz4-mz

				rx,ry,rz=cx6-cx5,cy6-cy5,cz6-cz5
				lr=(rx*rx+ry*ry+rz*rz)/r2-1
				avg,m=avg+lr*lr,lr/(lr*4+4)
				mx,my,mz=rx*m,ry*m,rz*m
				cx5,cy5,cz5=cx5+mx,cy5+my,cz5+mz
				cx6,cy6,cz6=cx6-mx,cy6-my,cz6-mz

				rx,ry,rz=cx8-cx7,cy8-cy7,cz8-cz7
				if Anchored8 then
					lr=(rx*rx+ry*ry+rz*rz)/r2-1
					avg,m=avg+lr*lr,lr/(lr*2+2)
					cx7,cy7,cz7=cx7+rx*m,cy7+ry*m,cz7+rz*m
				else
					lr=(rx*rx+ry*ry+rz*rz)/r2-1
					avg,m=avg+lr*lr,lr/(lr*4+4)
					mx,my,mz=rx*m,ry*m,rz*m
					cx7,cy7,cz7=cx7+mx,cy7+my,cz7+mz
					cx8,cy8,cz8=cx8-mx,cy8-my,cz8-mz
				end
				
				if avg/8<0.015625 then break end
			end
			--local asdf=tick()-asd--Actual bad names
			--print("Time to process physics: "..asdf)
		end


		local function DrawUpdate()
			--local asd=tick()
			local rx,ry,rz
			Part1.CFrame=cf(v3((cx0+cx1)/2,(cy0+cy1)/2,(cz0+cz1)/2),v3(cx1,cy1,cz1))
			Part2.CFrame=cf(v3((cx1+cx2)/2,(cy1+cy2)/2,(cz1+cz2)/2),v3(cx2,cy2,cz2))
			Part3.CFrame=cf(v3((cx2+cx3)/2,(cy2+cy3)/2,(cz2+cz3)/2),v3(cx3,cy3,cz3))
			Part4.CFrame=cf(v3((cx3+cx4)/2,(cy3+cy4)/2,(cz3+cz4)/2),v3(cx4,cy4,cz4))
			Part5.CFrame=cf(v3((cx4+cx5)/2,(cy4+cy5)/2,(cz4+cz5)/2),v3(cx5,cy5,cz5))
			Part6.CFrame=cf(v3((cx5+cx6)/2,(cy5+cy6)/2,(cz5+cz6)/2),v3(cx6,cy6,cz6))
			Part7.CFrame=cf(v3((cx6+cx7)/2,(cy6+cy7)/2,(cz6+cz7)/2),v3(cx7,cy7,cz7))
			Part8.CFrame=cf(v3((cx7+cx8)/2,(cy7+cy8)/2,(cz7+cz8)/2),v3(cx8,cy8,cz8))

			rx,ry,rz=cx1-cx0,cy1-cy0,cz1-cz0
			Mesh1.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx2-cx1,cy2-cy1,cz2-cz1
			Mesh2.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx3-cx2,cy3-cy2,cz3-cz2
			Mesh3.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx4-cx3,cy4-cy3,cz4-cz3
			Mesh4.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx5-cx4,cy5-cy4,cz5-cz4
			Mesh5.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)
	
			rx,ry,rz=cx6-cx5,cy6-cy5,cz6-cz5
			Mesh6.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx7-cx6,cy7-cy6,cz7-cz6
			Mesh7.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)

			rx,ry,rz=cx8-cx7,cy8-cy7,cz8-cz7
			Mesh8.Scale=v3(Thickness,Thickness,5*(rx*rx+ry*ry+rz*rz)^0.5)
			--local asdf=tick()-asd--Actual bad names
			--print("Time to process physics: "..asdf)
		end
		local RenderObject=RenderStepped:connect(function() AttachUpdate() PhysicsUpdate() DrawUpdate() end)

		return setmetatable({
			PositionAtLength=function(self,l)
				local d=l/Length*8
				if d<0 then
					return v3(c0x,c0y,c0z)
				elseif d<1 then
					local t=d-0
					return v3((cx1-cx0)*t+cx0,(cy1-cy0)*t+cy0,(cz1-cz0)*t+cz0)
				elseif d<2 then
					local t=d-1
					return v3((cx2-cx1)*t+cx1,(cy2-cy1)*t+cy1,(cz2-cz1)*t+cz1)
				elseif d<3 then
					local t=d-2
					return v3((cx3-cx2)*t+cx2,(cy3-cy2)*t+cy2,(cz3-cz2)*t+cz2)
				elseif d<4 then
					local t=d-3
					return v3((cx4-cx3)*t+cx3,(cy4-cy3)*t+cy3,(cz4-cz3)*t+cz3)
				elseif d<5 then
					local t=d-4
					return v3((cx5-cx4)*t+cx4,(cy5-cy4)*t+cy4,(cz5-cz4)*t+cz4)
				elseif d<6 then
					local t=d-5
					return v3((cx6-cx5)*t+cx5,(cy6-cy5)*t+cy5,(cz6-cz5)*t+cz5)
				elseif d<7 then
					local t=d-6
					return v3((cx7-cx6)*t+cx6,(cy7-cy6)*t+cy6,(cz7-cz6)*t+cz6)
				elseif d<8 then
					local t=d-7
					return v3((cx8-cx7)*t+cx7,(cy8-cy7)*t+cy7,(cz8-cz7)*t+cz7)
				else
					return v3(c8x,c8y,c8z)
				end
			end;

			Remove=function(self)
				Part1:Destroy()
				Part2:Destroy()
				Part3:Destroy()
				Part4:Destroy()
				Part5:Destroy()
				Part6:Destroy()
				Part7:Destroy()
				Part8:Destroy()
				RenderObject:disconnect()
				RenderObject=nil
				self.Remove=nil
				self.PositionAtLength=nil
				PositionUpdate=nil
				AttachUpdate=nil
				DrawUpdate=nil
				--What do I do about all of those variables I made? lol
				--Do I have to set each one to nil so that GC can delete the numbers?
				garbagecollect()
			end;
		},{
			__index=function(self,i)
				if i=="Length" then
					return Length
				elseif i=="Thickness" then
					return Thickness/5
				elseif i=="Material" then
					return Material
				elseif i=="Transparency" then
					return Transparency
				elseif i=="Reflectance" then
					return Reflectance
				elseif i=="BrickColor" then
					return BrickColor
				elseif i=="Parent" then
					return Model.Parent
				elseif i=="FrontPosition" then
					return v3(cx0,cy0,cz0)
				elseif i=="EndPosition" then
					return v3(cx8,cy8,cz8)
				elseif i=="FrontAnchored" then
					return Anchored0
				elseif i=="EndAnchored" then
					return Anchored8
				elseif i=="FrontAttach" then
					return Attach0
				elseif i=="EndAttach" then
					return Attach8
				elseif i=="FrontOffset" then
					return Offset0
				elseif i=="EndOffset" then
					return Offset8
				else
					error(i.." is not a valid member of Rope")
				end
			end;

			__newindex=function(self,i,v)
				if i=="Length" then
					Length=v
					r2=v*v/64
				elseif i=="Thickness" then
					Thickness=v*5
				elseif i=="Parent" then
					Model.Parent=v
				elseif i=="Material" then
					Material=v
					Part1.Material=v
					Part2.Material=v
					Part3.Material=v
					Part4.Material=v
					Part5.Material=v
					Part6.Material=v
					Part7.Material=v
					Part8.Material=v
				elseif i=="Transparency" then
					Transparency=v
					Part1.Transparency=v
					Part2.Transparency=v
					Part3.Transparency=v
					Part4.Transparency=v
					Part5.Transparency=v
					Part6.Transparency=v
					Part7.Transparency=v
					Part8.Transparency=v
				elseif i=="Reflectance" then
					Reflectance=v
					Part1.Reflectance=v
					Part2.Reflectance=v
					Part3.Reflectance=v
					Part4.Reflectance=v
					Part5.Reflectance=v
					Part6.Reflectance=v
					Part7.Reflectance=v
					Part8.Reflectance=v
				elseif i=="BrickColor" then
					BrickColor=v
					Part1.BrickColor=v
					Part2.BrickColor=v
					Part3.BrickColor=v
					Part4.BrickColor=v
					Part5.BrickColor=v
					Part6.BrickColor=v
					Part7.BrickColor=v
					Part8.BrickColor=v
				elseif i=="FrontPosition" then
					cx0,cy0,cz0=v.x,v.y,v.z
					Attach0=nil
				elseif i=="EndPosition" then
					cx8,cy8,cz8=v.x,v.y,v.z
					Attach8=nil
				elseif i=="FrontAnchored" then
					Anchored0=v
					if not v then
						Attach0=nil
						Offset0=v3()
					end
				elseif i=="EndAnchored" then
					Anchored8=v
					if not v then
						Attach8=nil
						Offset8=v3()
					end
				elseif i=="FrontAttach" then
					Attach0=v
					if v then
						Anchored0=true
					else
						Offset0=v3()
					end
				elseif i=="EndAttach" then
					Attach8=v
					if v then
						Anchored8=true
					else
						Offset8=v3()
					end
				elseif i=="FrontOffset" then
					Offset0=v
				elseif i=="EndOffset" then
					Offset8=v
				else
					error(i.." is not a valid member of Rope")
				end
			end;
		})
	end
end

--Example:
for i=1,12 do
	wait(0.1)
	local r=Rope.New()
	r.Length=1
	r.Thickness=0.1
	r.FrontAttach=game.Players.LocalPlayer.Character.Torso
	r.FrontOffset=Vector3.new(math.cos(i/12*6.28318)*0.75,2,math.sin(i/12*6.28318)*0.75)
	r.EndAnchored=false
end

Well, have fun!

Please make a weapon with this. :durrr: :open_mouth:

And the smart and charming FromLegoUniverse went through the dense and spooky forest of rope-ium…

This is what I got it to do so far

Oooh that’s pretty cool.

I updated the code. I was doing a lot of work with globals accidentally, so I fixed that. I also added a remove functions.

On remove, you’re doing Disconnect()

I did not test any of the code, but I’m pretty sure calling an event connection isn’t what you ment…
Disconnect:disconnect() is probably the thing you wanted to do :stuck_out_tongue:

You sir, are incredibly good at math :wink:

OH GOD. WHY DO I NOT TEST THESE THINGS. UGH.

Thank you!

I’m trying to attach a rope to the roof, and the bottom end to the container so it would hang from the rope. However the containers just fall down like theres no rope attached

Aftermath:

local ropeOrigin = workspace.ropeOrigin
local pos = ropeOrigin.Position
local ea = workspace.Container
local rope = Rope.new(workspace.Ignore)

rope.FrontAttach = ropeOrigin

if ea ~= nil then
	rope.EndAttach = ea.Value
	rope.Length = (e.Position - ea.Value.Position).magnitude
end

rope.EndAnchored = false

[quote] I’m trying to attach a rope to the roof, and the bottom end to the container so it would hang from the rope. However the containers just fall down like theres no rope attached

Aftermath:

[code]
local ropeOrigin = workspace.ropeOrigin
local pos = ropeOrigin.Position
local ea = workspace.Container
local rope = Rope.new(workspace.Ignore)

rope.FrontAttach = ropeOrigin

if ea ~= nil then
rope.EndAttach = ea.Value
rope.Length = (e.Position - ea.Value.Position).magnitude
end

rope.EndAnchored = false
[/code] [/quote]

They are decorative, the don’t interact with the world.

Oh.

:frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning: :frowning:

[quote] I’m trying to attach a rope to the roof, and the bottom end to the container so it would hang from the rope. However the containers just fall down like theres no rope attached

Aftermath:

[code]
local ropeOrigin = workspace.ropeOrigin
local pos = ropeOrigin.Position
local ea = workspace.Container
local rope = Rope.new(workspace.Ignore)

rope.FrontAttach = ropeOrigin

if ea ~= nil then
rope.EndAttach = ea.Value
rope.Length = (e.Position - ea.Value.Position).magnitude
end

rope.EndAnchored = false
[/code] [/quote]

They are decorative, the don’t interact with the world.[/quote]

Do you think there is an easy way to make them being able to hang objects?

The one thing that comes to my mind when demoing this: I could use this for long flowy hair.