Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

how to make a "Click to attach Rope" tool?

i was wondering if anyone knew how to make a tool that attaches a rope constraint to a Humanoid root part?

1 answer

✓ Accepted answer

Question

i was wondering if anyone knew how to make a tool that attaches a rope constraint to a Humanoid root part?

##Well here is how we do it. (This is going to be a lengthy post because I wanted to elaborate on everything.) pls accept took forever

First we want to insert a tool into StarterPack so any players that join get the tool. Then we can name the tool to anything we want. In my case I named it to "AttachTo". (In my demonstration I am not using a handle so we can disable the "RequiresHandle" property so the .Activated signal fires without a handle in the tool. ) Now that we have a tool we need it to work when the player activates it. First we will use a LocalScript because we need to be able to index the target of the players mouse to see what they clicked on. I named my local script "AttachToHandler_Client" because it handles the clientside for our AttachTo tool.

###The client side

Now that we have our localscript ready for editing, we need to be-able to send our mouse's target to the server. We can use remote events for this which seem complex but are pretty easily. You can learn more about remote events here aswell as here

We can get reference to our player on the client via the LocalPlayer property of the Player Service. To get a service we use game:GetService(serviceName) and it returns the service. So we can get reference to our players by defining a variable for the player's service and indexing LocalPlayer.

local players = game:GetService("Players")
local client = players.LocalPlayer

Now that we have reference to our player we can get reference to our mouse. We can use the :GetMouse method of a player instance. (This can only be called on the client). We will set a variable so we can easily index the properties of the mouse such as MouseTarget which is the instance the mouse is pointing at. (Sometimes nil if they are pointing at the sky)

local mouse = client:GetMouse()

After that we should define our tool; our tool will be the parent of the script since we put the script inside the tool, and connect a function to the Activated signal for our tool. We do this so everytime the tool is activated it fires the function. (We connect signals with the :Connect method and pass a function)

local tool = script.Parent

local function sendMouseTargetToServer()

end

tool.Activated:Connect(sendMouseTargetToServer)

We have defined our framework now to make it send the mouse's target to the server using a remote event. We will want to insert a "RemoteEvent" instance into our tool and name it "SendMouseTarget".

Now we can define the variable for our remote event and fire it when the function is called.

local tool = script.Parent
local sendMouseTargetEvent = tool:WaitForChild("SendMouseTarget")

local function sendMouseTargetToServer()
	sendMouseTargetEvent:FireServer(mouse.Target)
end

tool.Activated:Connect(sendMouseTargetToServer)

We have finished the client side.

###The server side

We will insert a "ServerScript" instance into our tool. I named it based off how we named our local script. I named mine "AttachToHandler_Server" because it handles the serverside.

We will need reference to the HumanoidRootPart from the serverside (we are doing this serverside so we don't have players trying to pass other people's HumanoidRootParts through or another instance.) We know the parent of the tool will be the player's backpack. We can then index the player from there, and then the character. With reference to the character we can index the character's HumanoidRootPart. (Also the character property of a player instance doesn't exist instantly so we have to yield until it exists if it doesn't already yet. player.Character or player.CharacterAdded:Wait())

local tool = script.Parent

local backpack = tool.Parent
local player = backpack.Parent

local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")

We will want to be able to receive the mousetarget so we will connect a function to the OnServerEvent signal of our remote event after we define our remote.

local sendMouseTarget = tool:WaitForChild("SendMouseTarget")

local function receiveMouseTarget(player, target)
	
end

sendMouseTarget.OnServerEvent:Connect(receiveMouseTarget)

Now we have our function's frame ready, we can start our other functions such as the function we will use to create attachments for the rope we are creating. We will pass a part through our makeAttachment and a position of where to place the attachment. Now we create the attachment with Instance.new and set its position to our passed position, and the parent to our passed part. Then we return the attachment so we can use it.


local function makeAttachment(part, pos)
	local attachment = Instance.new("Attachment") 
	local pos = pos or Vector3.new()
	
	attachment.Position = pos
	attachment.Parent = part
	
	return attachment
end

Next we make a function for connecting the rope to our root and the mouse target. We will create two attachments, the distance between the two parts passed, and the new rope we are creating to connect with the attachments.

We set the Attachment0 property of newRope to our attachment0 property and do the same for the Attachment1 property but use attachment1

Next we set the rope to visible so we can see it, and then we set the length to the distance between the part0 and part1 so they don't try to teleport inside eachother.

Finally we set the parent to one of the parts, in my case I just set it to part0

local function connectWithRopeConstraint(part0, part1)
	local newRope = Instance.new("RopeConstraint")
	local dist = (part0.Position - part1.Position).Magnitude
	
	local attachment0 = makeAttachment(part0)
	local attachment1 = makeAttachment(part1)
	
	newRope.Attachment0 = attachment0
	newRope.Attachment1 = attachment1
	
	newRope.Visible = true
	newRope.Length = dist
	
	newRope.Parent = part0
end

Now we go back to our receiveMouseTarget function since we have our rope function done. We want to check if the target exists so we don't try to index a nil value. Then we want to check if its a userdata so players don't try passing a table with a :IsA method and running unwanted code on the server. Once we know the target exists we check if its a basepart and if so continue and pass it in our connectWithRopeConstraint function with the root variable we have.

local sendMouseTarget = tool:WaitForChild("SendMouseTarget")

local function receiveMouseTarget(player, target)
	if type(target) == "userdata" and target then
		if target:IsA("BasePart") then
			connectWithRopeConstraint(root, target)
		end
	end
end

sendMouseTarget.OnServerEvent:Connect(receiveMouseTarget)

You may notice the player can spam the tool and potentially crash the server with an auto clicker.

We can add a debounce variable somewhere at the top and handle it in our receiveMouseTarget function.

local canUseMouseTargetReceived = true

-- rest of code

local function receiveMouseTarget(player, target)
	if canUseMouseTargetReceived then
		canUseMouseTargetReceived = false
		
		if type(target) == "userdata" and target then
			if target:IsA("BasePart") then
				connectWithRopeConstraint(root, target)
			end	
		end
		
		wait(1)
		canUseMouseTargetReceived = true
	end
end

The player can now only add a rope every 1 second. We are now finished.

The final code

###Client

local players = game:GetService("Players")

local client = players.LocalPlayer
local mouse = client:GetMouse()
local character = client.Character or client.CharacterAdded:Wait()

local tool = script.Parent
local sendMouseTargetEvent = tool:WaitForChild("SendMouseTarget")

local function sendMouseTargetToServer()
	sendMouseTargetEvent:FireServer(mouse.Target)
end

tool.Activated:Connect(sendMouseTargetToServer)

###Server

local tool = script.Parent

local backpack = tool.Parent
local player = backpack.Parent

local character = player.Character or player.CharacterAdded:Wait()
local root = character:WaitForChild("HumanoidRootPart")

local sendMouseTarget = tool:WaitForChild("SendMouseTarget")
local canUseMouseTargetReceived = true

local function makeAttachment(part, pos)
	local attachment = Instance.new("Attachment") 
	local pos = pos or Vector3.new()
	
	attachment.Position = pos
	attachment.Parent = part
	
	return attachment
end

local function connectWithRopeConstraint(part0, part1)
	local newRope = Instance.new("RopeConstraint")
	local dist = (part0.Position - part1.Position).Magnitude
	
	local attachment0 = makeAttachment(part0)
	local attachment1 = makeAttachment(part1)
	
	newRope.Attachment0 = attachment0
	newRope.Attachment1 = attachment1
	
	newRope.Visible = true
	newRope.Length = dist
	
	newRope.Parent = part0
end


local function receiveMouseTarget(player, target)
	if canUseMouseTargetReceived then
		canUseMouseTargetReceived = false
		
		if type(target) == "userdata" and target then
			if target:IsA("BasePart") then
				connectWithRopeConstraint(root, target)
			end	
		end
		
		wait(1)
		canUseMouseTargetReceived = true
	end
end

sendMouseTarget.OnServerEvent:Connect(receiveMouseTarget)

##Extra Uncopylocked place with all the sourcecode. Here

4 comments

0

Guys is my post epic

1

I counted 1,434 words and 9,744 characters. Good job.

0

Thanks Zafiura. I wanted to make sure they understood how the code worked aswell how to implement it before they used it.

0

Didn't have to write an essay.. lol good job

This discussion is preserved as it was. New answers, comments, and votes are closed.