Wallclimb system help

Please watch the video for what im explaining to make any sense: https://youtu.be/ZuV0_p4GLaE

Anyways as you can see in the video i have a wallclimb system which is not great but for my first time doing something like that im happy with it, it allows for you to switch walls while climbing. However as you can see that only works if the wall is directly to the right or left of the players root part. I would like to be able to switch walls in the second scenario shown in the video too. I am new to humanoid movers and dont know how to raycast in such a way to allow for what I want

local sript

local flyEvent = game.ReplicatedStorage:WaitForChild("Wall")
local UIS = game:GetService("UserInputService")

local RS = game:GetService("RunService")

local RParams = RaycastParams.new()
RParams.FilterType = Enum.RaycastFilterType.Exclude

local nearWall = false

UIS.InputBegan:Connect(function(input, gp)
	if gp or nearWall == false then return end
	
	if input.KeyCode == Enum.KeyCode.W then
		flyEvent:FireServer("Up", true)
	end
	
	if input.KeyCode == Enum.KeyCode.D then
		
		flyEvent:FireServer("Right", true)
	end
	
	if input.KeyCode == Enum.KeyCode.A then
		
		flyEvent:FireServer("Left", true)
	end
	
	if input.KeyCode == Enum.KeyCode.S then
		flyEvent:FireServer("Down", true)
	end

end)

UIS.InputEnded:Connect(function(input, gp)
	if gp or nearWall == false then return end

	if input.KeyCode == Enum.KeyCode.W then
		flyEvent:FireServer("Up", false)
	end

	if input.KeyCode == Enum.KeyCode.D then
		flyEvent:FireServer("Right", false)
	end

	if input.KeyCode == Enum.KeyCode.A then

		flyEvent:FireServer("Left", false)
	end

	if input.KeyCode == Enum.KeyCode.S then
		flyEvent:FireServer("Down", false)
	end

end)

repeat task.wait()
	
until game.Players.LocalPlayer.Character

RParams.FilterDescendantsInstances = {game.Players.LocalPlayer.Character}

local animationPlaying = false

local track = game.Players.LocalPlayer.Character.HumanoidRootPart.Parent.Humanoid.Animator:LoadAnimation(script.Animation)

local SwitchingWalls = false

RS.Heartbeat:Connect(function()
	local humanoidRootPart = game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
	if not humanoidRootPart then return end
	
	local raycastResult = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.LookVector * 1.3, 
		RParams
	)
	
	local raycastResultRight = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.RightVector * 1.3, 
		RParams
	)
	
	
	local raycastResultLeft = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.RightVector * -1.3, 
		RParams
	)

	if raycastResult and raycastResult.Instance then
		if raycastResult.Instance:GetAttribute("CanClimb") then
			if animationPlaying == false then
				track:Play()
				animationPlaying = true
			end
			nearWall = true
			if raycastResultLeft and raycastResultLeft.Instance and raycastResultLeft.Instance:GetAttribute("CanClimb") and SwitchingWalls == false  then
				SwitchingWalls = true
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResultLeft.Normal)
				task.wait(1)
				SwitchingWalls = false
			elseif raycastResultRight and raycastResultRight.Instance and raycastResultRight.Instance:GetAttribute("CanClimb") and SwitchingWalls == false then
				SwitchingWalls = true
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResultRight.Normal)
				task.wait(1)
				SwitchingWalls = false
			else
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResult.Normal)
			end
			
			
			end


	else
		
		if not raycastResult and not raycastResultLeft and not raycastResultRight then
			nearWall = false
			animationPlaying = false
			track:Stop()
			flyEvent:FireServer("Stop")
		end
	
	end
end)

server:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local flyEvent = ReplicatedStorage:WaitForChild("Wall")

local WHeld = false
local AHeld = false
local SHeld = false
local DHeld = false

local YPower = 0
local RightPower = 0

local lv
local humanoidRootPart
local character

Players.PlayerAdded:Connect(function(player)
	character = player.Character or player.CharacterAdded:Wait()
	humanoidRootPart = character:WaitForChild("HumanoidRootPart")

	local rootAttachment = humanoidRootPart:FindFirstChild("RootAttachment")
	if not rootAttachment then
		rootAttachment = Instance.new("Attachment")
		rootAttachment.Name = "RootAttachment"
		rootAttachment.Parent = humanoidRootPart
	end

	lv = Instance.new("LinearVelocity")
	lv.MaxForce = math.huge
	lv.RelativeTo = Enum.ActuatorRelativeTo.World
	lv.Parent = humanoidRootPart
	lv.VectorVelocity = Vector3.new(0, 0, 0)
end)

flyEvent.OnServerEvent:Connect(function(player, key, bool)
	lv.Attachment0 = humanoidRootPart.RootAttachment
	player.Character.Humanoid.AutoRotate = false
	
	
	if key == "Up" then
		if bool == true then
			YPower = 20
			WHeld = true
		else
			YPower = 0
			WHeld = false
		end
	end

	if key == "Down" then
		if bool == true then
			YPower = -20
			SHeld = true
		else
			YPower = 0
			SHeld = false
		end
	end

	if key == "Right" then
		if bool == true then
			RightPower = 20
			DHeld = true
		else
			RightPower = 0
			DHeld = false
		end
	end

	if key == "Left" then
		if bool == true then
			RightPower = -20
			AHeld = true
		else
			RightPower = 0
			AHeld = false
		end
	end

	if key == "Stop" then
		RightPower = 0
		YPower = 0
		lv.Attachment0 = nil
		WHeld = false
		SHeld = false
		DHeld = false
		AHeld = false
		player.Character.Humanoid.AutoRotate = true
	end
end)

repeat task.wait()
	
until character

local RParams = RaycastParams.new()
RParams.FilterType = Enum.RaycastFilterType.Exclude
RParams.FilterDescendantsInstances = {character}



game:GetService("RunService").Heartbeat:Connect(function()
	if lv then
		local rootCFrame = humanoidRootPart.CFrame
		
		local moveDirection = Vector3.new(RightPower, YPower, 0)
		local worldMoveDirection = rootCFrame:VectorToWorldSpace(moveDirection)
		lv.VectorVelocity = worldMoveDirection
		
		local raycastResultDown = workspace:Raycast(
			humanoidRootPart.Position,
			humanoidRootPart.CFrame.UpVector * -3, 
			RParams
		)
		
		local raycastResult = workspace:Raycast(
			humanoidRootPart.Position,
			humanoidRootPart.CFrame.LookVector * 2, 
			RParams
		)
		
		if raycastResultDown then
			if raycastResultDown.Instance then
				RightPower = 0
				YPower = 0
				lv.Attachment0 = nil
				WHeld = false
				SHeld = false
				DHeld = false
				AHeld = false
				character.Humanoid.AutoRotate = true
			end
		end
		
		
	end
end)

help is appreciated

2 Likes

Bumping as I still need help with this

Sorry that this initial reply isn’t helpful but im pretty sure you’re trying to detect a wall adjacent to the one you’re currently on right?

(for the second scenario)

As it’s shown in the video, yes I need to detect that wall using raycasts and position the player on it

1 Like

Okay so if you have a wall that is adjacent, it should be able to hit if you raycast in the direction of the LeftVector / RightVector of the wall the player is on from the wall’s position.

also sorry for the long wait. I had to really sit and think about how to solve this lol

so…

  • Raycast from the wall the player is currently on
  • Have 2 ray casts, one going left, one going right (LeftVector, RightVector)
  • Check if the ray hit anything, and if it is a valid surface

I’ve honestly got no idea what im talking about so if anyone more knowledgeable sees this, could you correct me?

Does not work. cant send the video because its too large but the character just randomly rotates and never switches walls correctly

1 Like

Yikes I hoped that would work. Can I go around and look for posts on this?

1 Like

I looked at just about every post about wallclimbing and none of them really helped me in the issue that I have. They all explain how to do just up down left right which I have working, none of them address the issue with changing walls that I have

1 Like

I don’t really have any other guesses other than rotating the position you’re raycasting from by 90deg and -90deg and moving it a little bit in that direction.

Hopefully some1 else can help

I tried that and the raycast’s did work but the player would never be orientated properly to the wall that it hit

1 Like

Couldn’t you make the character LookAt the wall that they’re climbing to?

Like

Char.HumanoidRootPart:LookAt(TheWall)
local flyEvent = game.ReplicatedStorage:WaitForChild("Wall")
local UIS = game:GetService("UserInputService")

local RS = game:GetService("RunService")

local RParams = RaycastParams.new()
RParams.FilterType = Enum.RaycastFilterType.Exclude

local nearWall = false

UIS.InputBegan:Connect(function(input, gp)
	if gp or nearWall == false then return end

	if input.KeyCode == Enum.KeyCode.W then
		flyEvent:FireServer("Up", true)
	end

	if input.KeyCode == Enum.KeyCode.D then

		flyEvent:FireServer("Right", true)
	end

	if input.KeyCode == Enum.KeyCode.A then

		flyEvent:FireServer("Left", true)
	end

	if input.KeyCode == Enum.KeyCode.S then
		flyEvent:FireServer("Down", true)
	end

end)

UIS.InputEnded:Connect(function(input, gp)
	if gp or nearWall == false then return end

	if input.KeyCode == Enum.KeyCode.W then
		flyEvent:FireServer("Up", false)
	end

	if input.KeyCode == Enum.KeyCode.D then
		flyEvent:FireServer("Right", false)
	end

	if input.KeyCode == Enum.KeyCode.A then

		flyEvent:FireServer("Left", false)
	end

	if input.KeyCode == Enum.KeyCode.S then
		flyEvent:FireServer("Down", false)
	end

end)

repeat task.wait()

until game.Players.LocalPlayer.Character

RParams.FilterDescendantsInstances = {game.Players.LocalPlayer.Character}

local animationPlaying = false

local track = game.Players.LocalPlayer.Character.HumanoidRootPart.Parent.Humanoid.Animator:LoadAnimation(script.Animation)

local SwitchingWalls = false

RS.Heartbeat:Connect(function()
	local humanoidRootPart = game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
	if not humanoidRootPart then return end

	local raycastResult = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.LookVector * 1.3, 
		RParams
	)

	local raycastResultRight = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.RightVector * 1.3, 
		RParams
	)

	local raycastResultLeft = workspace:Raycast(
		humanoidRootPart.Position,
		humanoidRootPart.CFrame.RightVector * -1.3, 
		RParams
	)
	
	local rayCastResultFrontRight = workspace:Raycast(
		humanoidRootPart.Parent.RightHand.Position,
		humanoidRootPart.CFrame.RightVector * -1.3,
		RParams
	)
	
	if raycastResult and raycastResult.Instance then
		if raycastResult.Instance:GetAttribute("CanClimb") then
			if animationPlaying == false then
				track:Play()
				animationPlaying = true
			end
			nearWall = true
			if raycastResultLeft and raycastResultLeft.Instance and raycastResultLeft.Instance:GetAttribute("CanClimb") and SwitchingWalls == false  then
				SwitchingWalls = true
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResultLeft.Normal)
				task.wait(1)
				SwitchingWalls = false
			elseif raycastResultRight and raycastResultRight.Instance and raycastResultRight.Instance:GetAttribute("CanClimb") and SwitchingWalls == false then
				SwitchingWalls = true
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResultRight.Normal)
				task.wait(1)
				SwitchingWalls = false
			elseif rayCastResultFrontRight and rayCastResultFrontRight.Instance and rayCastResultFrontRight.Instance:GetAttribute('CanClimb') and SwitchingWalls == false then
				SwitchingWalls = true
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -rayCastResultFrontRight.Normal)
				task.wait(1)
				SwitchingWalls = false
			else
				humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResult.Normal)
			end


		end


	else

		if not raycastResult and not raycastResultLeft and not raycastResultRight then
			nearWall = false
			animationPlaying = false
			track:Stop()
			flyEvent:FireServer("Stop")
		end

	end
end)

it detects the wall but i dont get aligned properly

1 Like

again I’m sorry for the late response (I forgot to check again). You might have to manually position the character like CFrame addition.

(My next response prolly gonna be delayed by an hour lol)

HumanoidRootPart.CFrame += CFrame.new(…)

Can you work that into the script I dont know how to position it correctly i tried it wasnt right

1 Like

im REALLY SORRY about delaying a response for 3 hours!! Completely forgot again :man_facepalming:

to

--[[ spaced out
so you can see
the change(s)
I made
]]

humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position,
humanoidRootPart.Position
+ -rayCastResultFrontRight.Normal
+ Vector3.new(10, 0, 0)
)

I chose (10, 0, 0) to move your character to the right a bit (hopefully I’m not tripping today)

So if I were you, I would just experiment with the numbers. But I’m pretty sure there’s a better way to make this type of thing if somebody who’s made one could come around

Tried it, does not work. You can stop wasting your time here I gave up on it a while ago before you responded anyways

1 Like

Alright. Sorry about wasting your day btw

You didn’t waste my time its just theres no point trying I cant get it to work i spent days

1 Like

Hey well if you’re willing to, maybe you could look at an open sourced project and try to learn from that?

Tried around 6. none of them had they all either didn’t have what I needed or just didn’t work

1 Like