Help with Wall Climb system

This is my first time, ever, working with any sort of body movers, so if you want to give an answer it has to be something simple, as i wont understand body mover terminology
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)
    lv.Attachment0 = humanoidRootPart.RootAttachment
    player.Character.Humanoid.AutoRotate = false

    -- Check for keypresses and movement
    if key == "Up" and not character:FindFirstChild("NearWall") then
        if WHeld == false then
            YPower = 20
            WHeld = true
        else
            YPower = 0
            WHeld = false
        end
    end

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

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

    if key == "Left" then
        if AHeld == false 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

    -- Handling stop of upward movement when near wall
    if key == "StopUp" then
        YPower = 0
        WHeld = false
    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
        )

        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)

Client:

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")
	end
	
	if input.KeyCode == Enum.KeyCode.D then
		
		flyEvent:FireServer("Right")
	end
	
	if input.KeyCode == Enum.KeyCode.A then
		
		flyEvent:FireServer("Left")
	end
	
	if input.KeyCode == Enum.KeyCode.S then
		flyEvent:FireServer("Down")
	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")
	end

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

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

		flyEvent:FireServer("Left")
	end

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

end)

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

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

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 * 5, 
		RParams
	)
	
	if raycastResult and raycastResult.Instance then
		if raycastResult.Instance:GetAttribute("CanClimb") then
			nearWall = true
		else
			nearWall = false
			flyEvent:FireServer("Stop")
		end
	else
		nearWall = false
		flyEvent:FireServer("Stop")
	end
end)

These 2 scripts have 2 main issues

  1. when you first approach a wall it will immediately start moving you until you reach the top of it, if you click S fast enough however it will stop and function properly

  2. The player is not aligned to the wall at all so its possible for him to be at an angle when he is climbing it

I have looked at just about every topic of wallclimbing on devforum and read the documentations they did not help.

Help is appreciated

to prevent the player randomly going up without pressing W you simply just have to implement a parameter in the flyEvent so that you can tell it whether you want to start moving in that direction or stop, for example for inputended you would use:

flyEvent:FireServer("Up", false)

and for inputbegan you would use:

flyEvent:FireServer("Up", true)

and also with this you can remove WHeld and the variables like it because ur gonna be deciding that when firing the remotes

to fix the player not facing the wall you can add this line of code under the line that sets nearWall to true:

humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -raycastResult.Normal)
1 Like

That fixed both my issues and wasn’t hard to implement, thanks

1 Like

can you look at this post also

im trying to make it work around certain types of corners