Need help with figuring out how to create pipe climbing system

I’m trying to make a PARKOUR inspired game and I’m really stuck on trying to figure out how to make the character latch onto the pipe and climb on it.

For instance, this is what I’m trying to recreate:

As you can see, when the player presses W or S, they go up/down the pipe. When they press space while looking at the pipe, they boost up for a second, and jump off if they’re not facing it.

I’ve seen some other games recreate this system similarly, so it shouldn’t be that hard to come up with a way to make the pipes behave like that, right? I have some code that detects when the player gets near a pipe, but I haven’t thought up of a way to make the player latch onto the pipe and climb it. I know I can use UserInputService to increase and decrease a value that could change the player’s position on the pipe.

(local script)

local plr = game.Players.LocalPlayer
local char = script.Parent
local hrp = char.HumanoidRootPart
local hum = char.Humanoid

local uis = game:GetService("UserInputService")
local run = game:GetService("RunService")

run.Heartbeat:Connect(function(dt)
	local ray = workspace:Raycast(hrp.Position,hrp.CFrame.LookVector * 3)
	local part = ray and ray.Instance or nil
	
	if part and part:HasTag("pipe") then
		-- pipe climbing code
	end
end)

And yes, I have already looked around on the forums, but I mainly created this post since either some posts didn’t help me a lot, or they talked about actual pipes, and there was no posts at all for a system like this.

If anyone could help figure it out and/or tell me what I should or shouldn’t be doing for pipe detection that would be very great!

1 Like

Just use a truss part its basically the same.

Do you even know what PARKOUR is? Hard no. Not using trusses at all.

I created something like this over a year ago. Some in-dev footage of what it looked like at the time (before any polish):

Key ingredients:

  • AlignPosition to make the player move up/down the pole
  • AlignOrientation to make the player rotate around the pole

These physics constraints are used to move and rotate the player. Both have their Mode set to OneAttachment and RigidtyEnabled is set to true.

To stick the player onto the pole at the right position, I check for a Touched event between the player’s RootPart and the pole and then find the closest position on the pole to the player’s RootPart. That’s where I attach them to the pole:

local function getClosestPointOnLine(startPoint: Vector3, endPoint: Vector3, point: Vector3)
	local lineVector = endPoint - startPoint
	local pointVector = point - startPoint
	local projectionLength = pointVector:Dot(lineVector.Unit)
	if projectionLength < 0 then
		return startPoint
	elseif projectionLength > lineVector.Magnitude then
		return endPoint
	else
		return startPoint + projectionLength * lineVector.Unit
	end
end

When I attach the player to the pole, I set a variable distanceOnLine to track where on the pole the player is located. I also clamp this variable so they can’t climb infinitely up/down.

local posOnLine = closestPointOnLine(poleBottom, poleTop, HRP.Position)
distanceOnLine = (posOnLine - poleBottom).Magnitude
poleLength = (poleBottom - poleTop).Magnitude
if distanceOnLine < 0 then distanceOnLine = 0 end
if distanceOnLine > poleLength then distanceOnLine = poleLength end

Once the player is attached I run a while loop to update the AlignPosition and AlignOrientation every frame.

while climbingThePole do
    local leftRight = 0
	if UserInputService:IsKeyDown(Enum.KeyCode.A) then -- rotating left
		leftRight = leftRight - 1
	end
	if UserInputService:IsKeyDown(Enum.KeyCode.D) then -- rotating right
		leftRight = leftRight + 1
	end
    AlignOrientation.CFrame = AlignOrientation.CFrame * CFrame.Angles(0, leftRight * ANGULAR_SPEED * dt, 0)

    local forward = 0
	if UserInputService:IsKeyDown(Enum.KeyCode.W) then -- climbing up
		forward = forward + 1
	end
	if UserInputService:IsKeyDown(Enum.KeyCode.S) then -- climbing down
		forward = forward - 1
	end

    distanceOnLine = distanceOnLine + forward
    if distanceOnLine < 0 then -- prevent player from climbing too far up/down
		distanceOnLine = 0
	elseif distanceOnLine > poleLength then
		distanceOnLine = poleLength
	end
    if climbingThePole then -- update the position on the pole
		AlignPosition.Position = poleBottom + (poleTop - poleBottom).Unit * distanceOnLine
	end
end

This is not the full code of course. For demonstration purposes I cut out a lot of stuff like mobile and gamepad controls, animation updates and so on. I believe you would be able to add those yourself. Obviously you will also want to make sure this code is all ran on the client, not on the server.

3 Likes

Thanks for the code, however how would I assemble all this to work for my game? Not sure if it’s because you cut out a lot of stuff but many variables are missing that I can’t make out and it’s pretty hard trying to piece it together considering most of it is just functions. Could you show me some more parts that could help me piece this together? Or is that too much to ask for?

Instead of explaining everything step for step I think it’s easier for us both if I give you an example place file. I tied together the things I said above into a place file with some extra code to make it all work. There’s a LocalScript inside the StarterCharacterScripts that makes the player climb any pipes they touch.

I tried to keep it very basic, but despite that there’s still a lot of code in there. I made sure to add comments to help you understand the ideas behind the code. A small caveat: This only works for pipes that are upright. If they are angled your character won’t rotate correctly. This also only supports keyboard controls as adding gamepad & mobile would almost double the amount of code.

climb_pipe_example.rbxl (55.7 KB)

Thanks a lot! I was able to make it behave how I want it to, but I still need help making it so the player always gets positioned in front of the pipe and not where ever they touched the pipe. By the way, I’m using normal (block) parts for the pipes, sorry I didn’t clarify that earlier.

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