Changing walls when WallClimbing 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

1 Like

Bump as I still need help with this

Second bump i still need help

30 letters

If you don’t know how start making any script, you can use Ai to find a solution for issues with your script in instance, maybe that can help you to be closer to find a solution!

Local Script Updates

  1. Raycasting in Multiple Directions: Add more raycasts around the player to form a "fan." These rays can point in directions slightly offset from the player’s right and left vectors.
  2. Choose Closest Wall: Identify the wall that is closest to the player and align the player’s HumanoidRootPart to face it.
  • Example Code for Extended Raycasting:*
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
local SwitchingWalls = false
local animationPlaying = false
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
RParams.FilterDescendantsInstances = {character}

local track = humanoidRootPart.Parent.Humanoid.Animator:LoadAnimation(script.Animation)

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

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

    if input.KeyCode == Enum.KeyCode.W then
        flyEvent:FireServer("Up", false)
    elseif input.KeyCode == Enum.KeyCode.D then
        flyEvent:FireServer("Right", false)
    elseif input.KeyCode == Enum.KeyCode.A then
        flyEvent:FireServer("Left", false)
    elseif input.KeyCode == Enum.KeyCode.S then
        flyEvent:FireServer("Down", false)
    end
end)

local function findClosestWall()
    local directions = {
        humanoidRootPart.CFrame.RightVector,                                -- Directly Right
        humanoidRootPart.CFrame.RightVector * -1,                           -- Directly Left
        humanoidRootPart.CFrame.RightVector + humanoidRootPart.CFrame.LookVector,  -- Forward-Right
        humanoidRootPart.CFrame.RightVector - humanoidRootPart.CFrame.LookVector,  -- Backward-Right
        humanoidRootPart.CFrame.RightVector * -1 + humanoidRootPart.CFrame.LookVector, -- Forward-Left
        humanoidRootPart.CFrame.RightVector * -1 - humanoidRootPart.CFrame.LookVector, -- Backward-Left
    }

    local closestWall = nil
    local closestDistance = math.huge

    for _, direction in ipairs(directions) do
        local result = workspace:Raycast(
            humanoidRootPart.Position,
            direction.Unit * 1.5,  -- Adjust range as needed
            RParams
        )
        if result and result.Instance and result.Instance:GetAttribute("CanClimb") then
            local distance = (result.Position - humanoidRootPart.Position).Magnitude
            if distance < closestDistance then
                closestDistance = distance
                closestWall = result
            end
        end
    end

    return closestWall
end

RS.Heartbeat:Connect(function()
    local closestWall = findClosestWall()
    if closestWall then
        if animationPlaying == false then
            track:Play()
            animationPlaying = true
        end

        nearWall = true

        if closestWall.Instance and not SwitchingWalls then
            SwitchingWalls = true
            humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + -closestWall.Normal)
            task.wait(1)
            SwitchingWalls = false
        end
    else
        nearWall = false
        animationPlaying = false
        track:Stop()
        flyEvent:FireServer("Stop")
    end
end)

Changes Incorporated:

  1. Extended Raycasting:
  • findClosestWall() now uses multiple raycasts to detect walls around the player.
  • It selects the closest wall by comparing distances.
  1. Wall Switching Logic:
  • Aligns the player’s HumanoidRootPart with the closest wall’s normal.
  • Prevents rapid switching with the SwitchingWalls flag.
  1. Improved Animation Handling:
  • Ensures animations play only when near a wall.

I tried using ai the code in wrote didn’t work, I gave it error messages and such but it still didn’t do what I want so I gave up on that. I have a new idea of setting 2 parts permanently to 2 studs infront and one to the left and the other to the right of the player and cast a ray on either their right or left vector to get the wall. Haven’t tried that I think it may work. Will do that tomorrow

okay, good luck! you can try this one and test it
:grin:

Bumping a third time I still need help

ohh… okay it’s not working (
try some AI to find - > issues, after that you can modify smth like you want