i was wondering if anyone knew how to make a tool that attaches a rope constraint to a Humanoid root part?
i was wondering if anyone knew how to make a tool that attaches a rope constraint to a Humanoid root part?
(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.
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.
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.
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)
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)
Uncopylocked place with all the sourcecode. Here
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?