How would I make a rope decrease in length more smoothly?

I’m currently using a while true do loop for it but it’s probably a bad idea. Here is a demonstration of what I have right now:

External Media

And here is my current script:

local replicated_storage = game:GetService("ReplicatedStorage")
local events = replicated_storage:WaitForChild("Events")
local grapple_event = events:WaitForChild("Grapple")
grapple_event.OnServerEvent:connect(function(player, type, attachment)
	local character = player.Character
	if (character) then
		local right_hand = character:WaitForChild("Right Arm")
		local root = character:WaitForChild("HumanoidRootPart")
		local grapple_attachment = right_hand:FindFirstChild("Grappleattach")
		if not (grapple_attachment) then
			grapple_attachment = Instance.new("Attachment")
			grapple_attachment.Name = "Grappleattach"
			grapple_attachment.Parent = right_hand
		end
		if (type == "create") then
			local rope = Instance.new("RopeConstraint", right_hand)
			rope.Attachment0 = grapple_attachment
			rope.Attachment1 = attachment
			rope.Visible = true
			rope.Archivable = true
			rope.Thickness = 0.2
			rope.Length = (root.Position - attachment.Parent.Position).Magnitude
			rope.Restitution = 1
			while true do
				wait(0.001)
				rope.Length = rope.Length - 1.5
			end
		elseif (type == "destroy") then
			local rope = right_hand:FindFirstChild("RopeConstraint")
			if (rope) then
				rope:Destroy()
			end
		end
	end
end)

This is my first time posting here by the way. If anything is wrong please let me know…

1 Like

The main thing you’d have to do is use the RunService to update the length each frame. Seems like you’d use the Stepped event for this.

I don’t like how you “exit” the while loop (delete the instance and cause the “thread” to fail).

This should make it smoother:

Replace:

while true do
	wait(0.001)
	rope.Length = rope.Length - 1.5
end

With:

while (rope and rope.Parent) do
	rope.Length -= (45*game:GetService("RunService").Heartbeat:Wait())
end

Also :connect is deprecated use :Connect.

Your suggestion does not make it smoother, it still does the same thing.

This is what I did to achieve “smooth” rope length decreasing.

https://streamable.com/sznt85

local runService = game:GetService("RunService")
local rope = script.Parent.RopeConstraint
local changePerSecond = 1

runService.Stepped:Connect(function(time, step)
  rope.Length -= changePerSecond * step  
end)

There is no other way to make it smoother. To make it smoother you would have to either decrease the increment or loop faster, but you cannot loop faster than 60 FPS (1/60) which is the limit of RunService.Heartbeat.

wait() minimum value is 30 FPS (1/30). Doing wait(0.001) is same as wait().

Also my method does make it smoother, it is just not noticeable since rope uses physics engine and that automatically smooths it out to 60 FPS in both cases.

I see. It seems like it’ll only be smooth if you use a reasonably small increment when decreasing the rope’s size. Thanks for the help though.

Have you considered tweening the length? It may give a smoother result than other solutions advised.

ie.

local TweenService = game:GetService("TweenService");

local tween_info = TweenInfo.new(2); --// Longer time will probably be better
local tween_goal = {
    Length = 0
};

local tween = TweenService:Create(rope, tween_info, tween_goal);
tween:Play();
4 Likes

Why would tweening result in a smoother result?

It looks a bit more smooth indeed. If no other solutions are found, I’ll just mark it as the solution. Thank you.

1 Like