Making a "Wall Climbing" System

I’ve not experimented much with wall climbing, but recently I have been trying to learn how to do it.

I find walls by raycasting. When a valid wall is found, I position the character’s primary part CFrame to the intersection point of the ray + the surface normal. Then, I change the humanoid state to PlatformStanding, zero the HumanoidRootPart’s velocity, and parent the necessary BodyMovers or constraints.

To align characters to walls, I usually use a BodyGyro. I set the CFrame property to the LookAt matrix constructed from the position of the HumanoidRootPart and the surface normal of the wall.

I handle movement using a BodyVelocity object. You can use different BodyMovers or Constraint objects depending on what exactly you are doing. To find the axes for movement for a BodyVelocity object, I find two vectors orthogonal to the surface normal of the wall. Then, based on value of the humanoid’s MoveDirection property I update the BodyVelocity to move the character accordingly along the wall.

If you want to keep them directly against the wall even with resistance, you can change the BodyVelocity for something like an AlignPosition object or something else, but if my character is getting pushed out of their state by an external force (like a moving part or other player), I cancel the state instead of trying to force them to remain aligned.

79 Likes

Would you mind elaborating on this a bit more? I understand the use of gyros and stuff but the part I’m more confused about is “set the CFrame property to the LookAt matrix constructed from the position of the HumanoidRootPart and the surface normal of the wall.”
It would also be much appreciated if you sent a gif or video of how this works out, and if it resembles the result I’d like.

4 Likes

You can use the CFrame constructor to create a rotation that is aligned with the wall. When you raycast, the third result is called the surface normal which will tell you the direction the surface you hit with the raycast is facing. If you set the BodyGyro’s CFrame property to CFrame.new(Vector3.new(), -normal) it would rotate to face the wall or surface you hit. Here is an example in action. (I didn’t have time to make animations for my character.)

https://gyazo.com/e962fd83e709eb701641a84cf489f25c

20 Likes

Thanks for explaining it, however, how would you make it so the climb is able to swap sides of an object when it reaches the end of one side as displayed in the video?
I really appreciate the help and patience, I’m sorry if I’m asking you to explain too much.

3 Likes

The simplest way I can think of right now is to check for different surfaces using raycasting when you update the player’s movement. As a more complex alternative (imo), you can get the adjacent surfaces of the wall or part and keeping track of the player’s position relative to the wall so that you can swap to the next adjacent surface when you reach the edge.

If you were going to use raycasting, however, I would suggest casting two rays pointing inward from the HumanoidRootPart’s sides, and updating the gyro / velocity / movement vectors to reflect the new surface the player moved to.

Here’s how that looks like:

https://gyazo.com/efae602748144d9b2765a05cfa54da1a

16 Likes

Hey, I’ve attempted this using a bodyposition and it appears that when the character latches on the characters bodyposition slowly shifts downwards.

External Media

I think it has something to do with how the ray is casted based on the rootpart’s lookvector, but I even tried using an attachment as the baseline for the raycast and it came up with the same result.

How exactly did you calculate where to position the character? (I likely missed it in an earlier reply and am just stupid but)
Code:

        hum.PlatformStand = true
		local bodypos = Instance.new("BodyPosition")
		bodypos.Name = "ClimbPosition"
		bodypos.D = 600
		bodypos.P = 10000
		bodypos.MaxForce = Vector3.new(10000,10000,10000)
		bodypos.Parent = root
		local bodygyro = Instance.new("BodyGyro")
		bodygyro.Name = "ClimbGyro"
		bodygyro.D = 600
		bodygyro.P = 100000
		bodygyro.MaxTorque = Vector3.new(30000,30000,30000)
		bodygyro.Parent = root
		repeat
			local start1 = root.CFrame
			local end1 = CFrame.new(attach.WorldPosition)
			local ray1 = Ray.new(start1.p, (end1.p - start1.p).unit * 2)
			local part1, position1,normal1 = workspace:FindPartOnRayWithIgnoreList(ray1, {char,workspace:WaitForChild("Effects")}, false, true)
			if part1 then
				if normal1 then
					bodypos.Position = position1 + normal1
					bodygyro.CFrame = CFrame.new(position1 + normal1,position1)
				end
			end
			wait(0.1)
		until climbing.Value == false or hum.Health == 0

Sorry for asking for help once again.

4 Likes

Hey

https://gyazo.com/a2d4914c5397d3bec980fc38acf8ec10.gif

The way I did the movement was to use a BodyVelocity. I would then use UserInputService to assign 1 and -1 to some variables in a dictionary.

local controls = {up = 0, down = 0, left = 0, right = 0}

Pressing W would be 1.
Pressing A would be -1 and S and D would be opposites of W and A.

Then I could just set the velocity of the BodyVelocity in a loop like this:

local Speed = 0.5

local movement = HumanoidRootPart.CFrame:VectorToWorldSpace(Vector3.new(controls.left + controls.right, controls.up + controls.down, 0)) * Speed

Which gave me this result:
https://gyazo.com/80a45b94f720cd435e26bb7f7d300118.gif

Whenever the player isn’t pressing WASD, you just gotta set BodyVelocity.Velocity = Vector3.new(0,0,0) to have the Player “stand still”.

https://gyazo.com/2c46bf9b2e8a998f403fac3403e1b594.gif

Credit, props and thanks to @JimmyChance for helping me out as well :smiley:

8 Likes

Thanks for the help, that definitely looks great. However, a bodyvelocity is too “flimsy” and unresponsive compared to the result I want. It seems to skid along the wall rather than actually sternly climb. However, how did you keep the player on the wall whilst only using a bodyvelocity? That part confuses me.

If you use BodyVelocity, make sure that it has a high enough MaxForce property. At a high enough MaxForce, the object that the BodyVelocity is parented to will instantaneously accelerate to match the BodyVelocity’s Velocity property. (If BodyVelocity’s Velocity property is the zero vector, the object will be stationary.)

3 Likes

Yes, I realized that now. However, again, how are you keeping the player against the wall while they move?

2 Likes

In my case, after initially positioning the character, I make sure the BodyVelocity’s Velocity property is applied parallel to the wall so they maintain their distance from it.

2 Likes

That’s one of my issues right now. I actually don’t keep the player against the wall. The way I’ve been doing it is to rotate the player accordingly to the surface normal of the current part of the wall, which would make the player go parallel with the wall, however this is not optimal. Since the rotation takes some time, this will overtime make the player get further and further away from the wall, as you can see here:

https://gyazo.com/2c46bf9b2e8a998f403fac3403e1b594.gif

Notice how the player is up against the wall in the beginning, but by the end, is like 1-2 studs away from the wall.

As @JimmyChance has confirmed, positioning/CFraming the player first and then applying the velocity afterwards is a way to go about this issue, which is something I’ll try to apply to my system today. I’ll probably tween the CFrame so it seems smooth :smiley:

4 Likes

Hey how were you able to do that wall climbing thing because I really wanted to learn how, thanks!

1 Like

I made something like this a while ago, and also shared it on an identical post.

Feel free to copy.

14 Likes

can you help me about RayCasting? when pressing WASD mine is buggy.

1 Like

Ill try this out thanks alot this will def help!

1 Like

It’s still really hard to understand the code and everything thats going on could you explain it?

2 Likes

It’s Been 7 months but I need help for the BodyGyro Position to go to different surfaces.

2 Likes

Can you give us the script or uncopylock a game? Just a question.

2 Likes

If Possible to give the Uncopylocked version of the game would be helpful. Its okay if not possible.

1 Like