BodyPosition slowing down

Hello! I am trying to make a zipline for my game, but the character moves slower when it reaches a point.

Trying to lower the Dampening property and rise the Power property this happens:

Why does this happen and is there any way to fix it?

3 Likes

The issue isn’t the BodyPosition, but the bezier curve itself

Since bezier curves don’t have equal distances between each bezier point, tighter curves are gonna have a slower speed since all those points in the curve are so close to each other

2 Likes

Ah, I see, is there any way to fix it though?

1 Like

There’s a couple ways to do it for ex:

You can get the current bezier point and the next bezier point and get the distance

 local distance = (currentPoint - nextPoint).Magnitude

And then after you can divide that distance by how fast you want to travel

 local distance = (currentPoint - nextPoint).Magnitude
 local speed = distance / 40

There’s also another way called arc length parameterization but I won’t go into it since it’s a bit more complicated and involves a lot of math

1 Like

I just realized I forgot the script! Here it is:

local speed = 0

	local posPoints = {}

	for i=1, #points do
		if i > 1 then
			speed += (points[i - 1].Position - points[i].Position).Magnitude * 1.3
		end
		table.insert(posPoints, points[i].Position)
	end

	if rope:FindFirstChild("Settings") then
		if rope.Settings:FindFirstChild("ExtraSpeed") then
			speed = speed / rope.Settings.ExtraSpeed.Value
		end
	end

	coroutine.wrap(EnableCamera)()

	local inc = (1 /(speed))

	local this
	local Distance

	for t = 0, 1 - inc, inc do
		local pos = Bezier.GetBezierPoint(t, unpack(posPoints))
		local nextPos = Bezier.GetBezierPoint(t + inc, unpack(posPoints))
		Distance = (pos - nextPos).magnitude
		this = CFrame.lookAt(pos, nextPos, Vector3.new(0, 1, 0)) * CFrame.new(0, -2, Distance / -2)
		bodyPos.Position = this.Position
		bodyGy.CFrame = this * CFrame.new(0, -2, -Distance / 2)
		part.CFrame = this
		task.wait()
	end
1 Like

the local speed is part of it, just dont know why it looks like that

That’s some code but if I were you, I would put this inside a Heartbeat loop

Here’s how I did mine:
bezier_test.rbxl (54.5 KB)

3 Likes

FYI, that isn’t the full script. I will send the full script tomorrow and I hope you reply. :smiley:

1 Like

Full scripts:

_zipline:

local plr = game.Players.LocalPlayer
local Bezier = require(game.ReplicatedStorage.GameScripts.Ziplines.Bezier)
local zipAnim = game.ReplicatedStorage.AnimationStorage.Swing
local travelling = false
local D = 0

function DisableSparkles()
	local sparkles = plr.Character["Right Arm"].Sparkles
	sparkles.Enabled = false
	wait(4)
	sparkles:Destroy()
end

function DisableBodyStuff()
	local bodyPos = plr.Character.HumanoidRootPart.BodyPosition
	local bodyGy = plr.Character.HumanoidRootPart.BodyGyro
	wait(0.04)
	bodyPos:Destroy()
	bodyGy:Destroy()
	for i, v in pairs(plr.Character:GetDescendants()) do
		if v:IsA("Part") and v.Name ~= "HumanoidRootPart" then
			v.CollisionGroup = "PlayerChars"
		end
	end
	if game.ReplicatedStorage.ClientConfig.ZiplineCameraEnabled.Value then
		workspace.CurrentCamera.CameraSubject = plr.Character.Humanoid
		workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
		plr.CameraMaxZoomDistance = 400
		plr.CameraMinZoomDistance = 0.5
	end
end

function EnableCamera()
	if game.ReplicatedStorage.ClientConfig.ZiplineCameraEnabled.Value then
		plr.CameraMinZoomDistance = 10
		plr.CameraMaxZoomDistance = 10
		workspace.CurrentCamera.CameraSubject = plr.Character.Humanoid
		workspace.CurrentCamera.CameraType = Enum.CameraType.Watch
	end
end

function travelPoints(points, rope)
	travelling = true
	local humAnim = plr.Character.Humanoid:LoadAnimation(zipAnim)

	local part = Instance.new("Part", plr.Character)
	part.Anchored = true
	part.CanCollide = false
	part.Transparency = 1

	local tag = Instance.new("IntValue", plr.Character)
	tag.Name = "RidingZipline"

	local sparkles = Instance.new("Sparkles", plr.Character["Right Arm"])
	sparkles.SparkleColor = Color3.fromRGB(255, 179, 0)
	
	local bodyPos = Instance.new("BodyPosition", plr.Character.HumanoidRootPart)
	bodyPos.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
	bodyPos.P = 50000000	
	bodyPos.D = 0

	local bodyGy = Instance.new("BodyGyro", plr.Character.HumanoidRootPart)
	bodyGy.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
	bodyGy.P = 50000
	bodyGy.D = 50

	humAnim:Play()

	game.SoundService.ZiplineOn.TimePosition = 0.5
	game.SoundService.ZiplineOn.Playing = true
	game.SoundService.Zipline.Playing = true

	local speed = 0

	local posPoints = {}

	for i=1, #points do
		if i > 1 then
			speed += (points[i - 1].Position - points[i].Position).Magnitude * 1.3
		end
		table.insert(posPoints, points[i].Position)
	end

	if rope:FindFirstChild("Settings") then
		if rope.Settings:FindFirstChild("ExtraSpeed") then
			speed = speed / rope.Settings.ExtraSpeed.Value
		end
	end

	coroutine.wrap(EnableCamera)()

	local inc = (1 /(speed))

	local this
	local Distance

	for t = 0, 1 - inc, inc do
		local pos = Bezier.GetBezierPoint(t, unpack(posPoints))
		local nextPos = Bezier.GetBezierPoint(t + inc, unpack(posPoints))
		Distance = (pos - nextPos).magnitude
		this = CFrame.lookAt(pos, nextPos, Vector3.new(0, 1, 0)) * CFrame.new(0, -2, Distance / -2)
		bodyPos.Position = this.Position
		bodyGy.CFrame = this * CFrame.new(0, -2, -Distance / 2)
		part.CFrame = this
		task.wait()
	end

	bodyPos.Position = this.Position
	bodyGy.CFrame = this * CFrame.new(0, -2, -Distance / 2)
	
	coroutine.wrap(DisableBodyStuff)()
	part:Destroy()
	tag:Destroy()
	coroutine.wrap(DisableSparkles)()
	game.SoundService.Zipline.Playing = false
	game.SoundService.ZiplineOff.TimePosition = 0.5
	game.SoundService.ZiplineOff.Playing = true
	humAnim:Stop()
	travelling = false
end

function sort(tab)
	local finished = {}
	for i=1, #tab do
		for x=1, #tab do
			if tonumber(string.sub(tab[x].Name, 6, #tab[x].Name)) == i then
				finished[i] = tab[x]
			end
		end
	end
	return finished
end

for _,i in ipairs(plr.Character:GetChildren()) do
	if i:IsA("BasePart") then
		i.Touched:Connect(function(p)
			if p.Name == "StartPoint" and p.Parent.Name == "_Rope" and not travelling then
				local points = {}
				for _,x in ipairs(p.Parent:GetChildren()) do
					if string.find(x.Name, "Point") then
						table.insert(points, x)
					end
				end
				for i, v in pairs(plr.Character:GetDescendants()) do
					if v:IsA("Part") and v.Name ~= "HumanoidRootPart" then
						v.CanCollide = false
						v.CollisionGroup = "Zipline"
					end
				end
				points = sort(points)
				travelPoints(points, p.Parent)
			end	
		end)	
	end
end

Bezier:

local module = {}


function Lerp(P0, P1, T)
	return (1 - T) * P0 + T * P1
end

function module.GetBezierPoint(T, ...)
	local Points = {...}

	while (#Points > 1) do
		for i = 1, #Points - 1 do
			Points[i] = Lerp(Points[i], Points[i + 1], T)
		end

		Points[#Points] = nil
	end

	return Points[1]
end

function createPart(Point, NextPoint, Parent)
	local ZiplinePart = Instance.new("Part")

	ZiplinePart.Anchored = true
	ZiplinePart.Size = Vector3.new(0.25, 0.25, (Point - NextPoint).Magnitude)
	ZiplinePart.CFrame = CFrame.lookAt(Point, NextPoint, Vector3.new(0, 1, 0)) * CFrame.new(0, 0, ZiplinePart.Size.Z / -2)
	ZiplinePart.Material = "Fabric"
	ZiplinePart.Color = Color3.new(0, 0, 0)
	ZiplinePart.Parent = Parent
	ZiplinePart.CanCollide = false

	return ZiplinePart
end

function module.new(par, ...)
	local points = {...}
	local posPoints = {}
	local speed = 0
	for i=1, #points do
		table.insert(posPoints, points[i].Position)
		if i > 1 then
			speed += (points[i - 1].Position - points[i].Position).Magnitude * 1.3
		end
	end
	
	local inc = (1 / 40)
	
	for i = 0, 1.0025 - inc, inc do
		local Point = module.GetBezierPoint(i, unpack(posPoints))
		local NextPoint = module.GetBezierPoint(i + inc, unpack(posPoints))
		createPart(Point, NextPoint, par)
	end
end

return module

I tried switching to this one and it works so much better! Thank you so much for helping me!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.