Help with zipline sytem

I’m working on a zipline creating system using a tool that fires a projectile hook forward until it hits something and so far its worked fine. However, for some reason the hook offsets to the side upon contact yet I’m not sure why. I’m using bodyvelocity to propel it towards wherever the player has clicked (I know this has been replaced with alignposition but I find it easier to use). Any help would be greatly appreciated as I’m really not sure what I’ve done wrong here.

the local script

local GrappleGun = script.Parent
local CanUse = true

GrappleGun.Equipped:Connect(function(Mouse)
Mouse.TargetFilter = game.Workspace.Ammunition
Mouse.Button1Down:Connect(function()
if CanUse then
game.ReplicatedStorage.FireGrapple:FireServer(Mouse.Hit.Position, GrappleGun)
CanUse = false
wait(1)
CanUse = true
end
end)
end)

the server script

local RS = game:GetService(“RunService”)
local UIS = game:GetService(“UserInputService”)

game.ReplicatedStorage.FireGrapple.OnServerEvent:Connect(function(Plr, MousePosition, GrappleGun)
if game.Workspace.Ammunition:FindFirstChild(Plr.Name…"'s_GrappleHook") then
game.Workspace.Ammunition:FindFirstChild(Plr.Name…"'s_GrappleHook"):Destroy()
end
local HasHit = false
local GrappleHook = game.ReplicatedStorage.GrappleHook:Clone()
GrappleHook.Parent = game.Workspace.Ammunition
GrappleHook.CFrame = CFrame.new(GrappleGun.Crossbow.GrappleHook.Position, MousePosition)
GrappleHook.Name = Plr.Name…"'s_GrappleHook"
local StartPart = Instance.new(“Part”)
StartPart.Parent = GrappleHook
StartPart.Position = GrappleGun.Crossbow.GrappleHook.Position
StartPart.Anchored = true
StartPart.CanCollide = false
StartPart.Transparency = 1
local Attachment0 = Instance.new(“Attachment”)
Attachment0.Parent = GrappleHook
local Attachment1 = Instance.new(“Attachment”)
Attachment1.Parent = StartPart
local Zipline = Instance.new(“Beam”)
Zipline.Parent = GrappleHook
Zipline.Attachment0 = Attachment0
Zipline.Attachment1 = Attachment1
Zipline.FaceCamera = true
Zipline.Width0 = 0.5
Zipline.Width1 = 0.5
Zipline.Color = ColorSequence.new(Color3.fromHSV(0,0,0))
Zipline.Transparency = NumberSequence.new({
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(0.5, 0),
NumberSequenceKeypoint.new(1, 0)
}
)

local BodyVelocity = Instance.new(“BodyVelocity”, GrappleHook)
BodyVelocity.Velocity = CFrame.new(GrappleHook.Position, MousePosition).LookVector * 50

GrappleHook.Touched:Connect(function(Part)
if Part:IsDescendantOf(game.Workspace.Map) then
print(Part)
BodyVelocity:Destroy()
GrappleHook.Anchored = true
HasHit = true
local Prompt1 = Instance.new(“ProximityPrompt”)
Prompt1.Parent = StartPart
Prompt1.Triggered:Connect(function(Zipliner)
local Pulley = game.ReplicatedStorage.Pulley:Clone()
Pulley.Parent = game.Workspace
Pulley.Body.CFrame = CFrame.new(StartPart.Position, GrappleHook.Position)
local BodyVelocity2 = Instance.new(“BodyVelocity”)
BodyVelocity2.Parent = Pulley.Body
BodyVelocity2.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
BodyVelocity2.Velocity = (Plr.Character.HumanoidRootPart.Position - GrappleHook.Position).Unit * -10
local BodyGyro = Instance.new(“BodyGyro”)
BodyGyro.Parent = Pulley.Body
BodyGyro.CFrame = CFrame.new(StartPart.Position, GrappleHook.Position)
local Weld1 = Instance.new(“WeldConstraint”)
Weld1.Parent = Zipliner.Character
Weld1.Part1 = Pulley.Body
Weld1.Part0 = Zipliner.Character.RightHand
Plr.Character.HumanoidRootPart.CFrame = CFrame.new(StartPart.Position, GrappleHook.Position)
UIS.InputBegan:Connect(function(Key)
if Key.KeyCode == Enum.KeyCode.Space then
end
end)
RS.Heartbeat:Connect(function()
if (Plr.Character.HumanoidRootPart.Position - GrappleHook.Position).Magnitude < 2 then
print(“in range”)
if Plr.Character.HumanoidRootPart:FindFirstChild(“BodyVelocity”) then
Plr.Character:FindFirstChild(“HumanoidRootPart”):FindFirstChild(“BodyVelocity”):Destroy()
end
end
end)
end)
end
end)

local Origin = StartPart.Position
local Direction = StartPart.CFrame.LookVector * 30

local NewRay = Ray.new(Origin, Direction)

local MidPoint = NewRay.Origin + NewRay.Direction/2

local Part = Instance.new(“Part”)
Part.Parent = StartPart
Part.Anchored = true
Part.CanCollide = false
Part.Name = “ZiplinePole”
Part.CFrame = CFrame.new(NewRay.Origin, MidPoint)
Part.Size = Vector3.new(1, NewRay.Direction.Magnitude, 1)
Part.Transparency = 0
end)

1 Like

A few things, I know that you stated that you find your current approach easier, but I believe you will find AlignPosition (roblox.com) a lot better than using your current method.

Secondly, you are using BodyVelocity (roblox.com) which has been replaced by LinearVelocity (roblox.com), which is also very easy to use.

Using AlignPosition will most likely solve your issues without changing a lot of the other stuff. I’d recommend experimenting with it a bit.

Lastly, to format your code, write “```” on the line before and after your code. It makes it scrollable and easier to read.

1 Like

alright I’ll do this, thank you

If you require any help on how to use either of these, let me know and I’ll do my best to help you!

1 Like

I’ve tried using both methods you’ve suggested but neither have worked, can you provide an example of how they should be used for this?

Of course! AlignPosition will act somewhat weird, as it will slow down as it approaches the target, but it is very easy to use.

-- AlignPosition code example:
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()

function fireGrapple()
	local tgt = mouse.Hit.Position -- Raycast result position
	local grapple = Instance.new("Part")

	local attachment0 = Instance.new("Attachment")
	attachment0.Parent = grapple 
	
	local attachment1 = Instance.new("Attachment")
	attachment1.Parent = workspace.TestWall-- This should be the part hit (Obtained from Raycast)
	attachment1.WorldPosition = tgt -- Move it to the correct position

	
	local align = Instance.new("AlignPosition")
	align.Attachment0 = attachment0
	align.Attachment1 = attachment1
	align.ApplyAtCenterOfMass = true
	align.Parent = grapple
	
	grapple.Position = Vector3.new(5, 5, 5)
	grapple.Parent = workspace
end


mouse.Button1Down:Connect(function()
	fireGrapple()
end)

Combining the above with an AlignOrientation (roblox.com) would prevent it from rotating whatsoever, and would provide a pretty easy solution.

-- Linear velocity example
local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()

function fireGrapple()
	local tgt = mouse.Hit.Position
	local startPosition = Vector3.new(5, 5, 5) -- Example start pos
	local StudsPerSec = 20
	
	local grapple = Instance.new("Part")

	local attachment0 = Instance.new("Attachment")
	attachment0.Parent = grapple
	
	local velocity = Instance.new("LinearVelocity")
	velocity.MaxForce = math.huge -- Might not be able to move it otherwise
	velocity.RelativeTo = Enum.ActuatorRelativeTo.World
	velocity.VectorVelocity = (tgt - startPosition).Unit * StudsPerSec -- (EndPoint - StartPoint) = Direction. Calling .Unit allows you to set a specific speed.
	velocity.Attachment0 = attachment0
	velocity.Parent = grapple
	
	grapple.Position = startPosition
	grapple.Parent = workspace
end


mouse.Button1Down:Connect(function()
	fireGrapple()
end)

For this one you would need to register when it touches something, as it will just continue traveling in the same direction indefinitely otherwise. Combine this with an AlignOrientation as well for best result. Using AlignOrientation is very similar to the way these are used. It requires an attachment. I would recommend setting AlignOrientation.Responsiveness = 200 to make it very responsive.

NOTE: I am using mouse.Hit.Position instead of raycasting, as this was quicker and still demonstrates how to use the bodymover.

1 Like