Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

how to make a "Click to attach Rope" tool? [closed]

Asked by 6 years ago

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

Locked by User#24403

This question has been locked to preserve its current state and prevent spam and unwanted comments and answers.

Why was this question closed?

1 answer

Log in to vote
5
Answered by 6 years ago
Edited 6 years ago

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

0
Guys is my post epic EpicMetatableMoment 1444 — 6y
1
I counted 1,434 words and 9,744 characters. Good job. Zafirua 1348 — 6y
0
Thanks Zafiura. I wanted to make sure they understood how the code worked aswell how to implement it before they used it. EpicMetatableMoment 1444 — 6y
0
Didn't have to write an essay.. lol good job Nickelz 37 — 6y
Ad