How to detect when player is at the end of a zipline? and stop their velocity? [HELP]

I’ve tried everything and nothing works.

  1. putting touched event hitbox that is big at the end of the zipline to detect that the player reached the end (Doesn’t work, unresponsive and overshoots)

  2. using physics math to calculate the time it will take for the player to reach the end (not quite its always too early and finishes the zipline at the wrong time ( Doesn’t reach the end in time))

  3. comparing the players distance along the way of the two poles using magnitude (still overshoots)

what should I do? i’ve done everything i can and it doesn’t work probably because of roblox’s inaccuracy.

https://gyazo.com/70fece616344cd9924b066e907566430

overshoots

the velocity on the zipline uses bodyvelocity “Bv” in the code and accelerates using the slope angle of the zipline

-- Server script
if IsPastEnd(char.HumanoidRootPart.Position,Attachment_A.WorldPosition,Attachment_B.WorldPosition) then
	Ziplining[char.Name] = false
	Bv:Destroy()

	char.HumanoidRootPart.Velocity = Vector3.new(0,0,0)
	print("works")
end

heres my entire code

-- Server script

local A_Prompt = Instance.new("ProximityPrompt",script.Parent.A.Part0)

A_Prompt.ActionText = "Zipline"

A_Prompt.MaxActivationDistance = 4

A_Prompt.HoldDuration = .25

local speed = 0
local maxspeed = 120

local Zipline = script.Parent

local Attachment_A = Zipline.A.Part0.Attachment1
local Attachment_B = Zipline.B.Part0.Attachment0

local Ziplining = {}

local function IsPastEnd(pos, a, b)
	local distance = (a-b).magnitude
	local playerdistance = (a-pos).magnitude
	return playerdistance >= distance 
end

A_Prompt.Triggered:connect(function(plr)

	local char = plr.Character

	if not Ziplining[char.Name] then
		local Lookvector = (Attachment_B.WorldPosition - Attachment_A.WorldPosition).unit

		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.FilterDescendantsInstances = {char}

		if Lookvector.Y <= 0 then
			print("goes down")

			Ziplining[char.Name] = true

			local Y_dist = Attachment_B.WorldPosition.Y - Attachment_A.WorldPosition.Y

			if Y_dist < 0 then
				Y_dist = Y_dist * -1
			end

			local slopeangle = math.deg(math.atan((Y_dist)/(Attachment_A.WorldPosition-Attachment_B.WorldPosition).magnitude))

			local acceleration = (math.sin(slopeangle) * workspace.Gravity)
			
			if acceleration < 0 then
				acceleration = acceleration * -1
			end
			
			local accelerationrate = acceleration * 0.03

			print(slopeangle)
			print(accelerationrate)

			local char = plr.Character

			char:SetPrimaryPartCFrame(CFrame.new(Attachment_A.WorldPosition + Lookvector*1.5 - Vector3.new(0,1,0)))
			char.HumanoidRootPart.CFrame = CFrame.lookAt(char.HumanoidRootPart.CFrame.Position,Attachment_B.WorldPosition)

			Bv = Instance.new("BodyVelocity",char.HumanoidRootPart)

			local currentspeed = speed

			Bv.MaxForce = Vector3.new(1,1,1) * 500000

			while currentspeed < maxspeed and wait() and Ziplining[char.Name] do
				currentspeed = currentspeed + accelerationrate
				Bv.Velocity = Lookvector * currentspeed
					
				if IsPastEnd(char.HumanoidRootPart.Position,Attachment_A.WorldPosition,Attachment_B.WorldPosition) then
					Ziplining[char.Name] = false
					Bv:Destroy()

					char.HumanoidRootPart.Velocity = Vector3.new(0,0,0)
					print("works")
				end
			end
		else
			print("Can't use zipline")
		end
	end
end)

I bet this post is gonna be lost with no replies

I’m no scripter, but perhaps you can put a hitbox close to the end of the line that gradually slows down your velocity?

If NOTHING works at all, you could probably go for the buggy method of “just putting an anchored part at the end of the zipline” and then deleting that part once it’s touched

This system is a bit unreliable Id imagine, I would instead do something like

while currentspeed < maxspeed and Ziplining[char.Name] do
    local dt = runservice.Stepped:Wait()
    currentspeed = currentspeed + acceleration * dt
    
    ...
end

The bodyvelocity could also be a bit unreliable, you could try using applyimpulse but that might get a bit s h a k y
You could also just use a force and f=ma, calculating the force applied straight along the zipline as:

bodyforce.Force = ziplineVector * hrp.AssemblyMass * acceleration

That should accelerate it at the desired rate without the use of any loops or anything fancy, maybe try making 0 friction too if you havent already

what if instead of using bodyvelocity i just using tweening instead? could that potentially solve this problem?

Tweens cant accelerate easily
Its possible you could use the position function to generate an alpha value

So

position(t) = 1/2 * a * t^2
Then divide that by the max position and you have an alpha value
You would then have to calculate the time using the inverse of the position function like I explained earlier, then somehow make that change in alpha happen over that period of time
Theres multiple ways you could do this, the easiest of which would just be like a while loop or something
That would definitely remove the physics system badness

local pos = 0
local t = 0
local max_t = math.sqrt(2 * a/length_of_zipline)
while pos < length_of_zipline do
    local dt = runservice.Heartbeat:Wait()
    t = t + dt
    alpha = (1/2 * a * t^2)/length_of_zipline
    position = (endpoint_zipline-startpoint_zipline)*alpha+startpoint_zipline
end

Maybe just anchor the player for a second after you destroy the BodyVelocity

Edit: Or instead of touched you could do ZonePlus

You could probably try Region3 usually works for me

You could find out how long it takes for a player to travel to the end, then set velocity to 0,0,0.