Wall Climb Lags When Switching Edges

I created this Wall Climb System however it lags when switching surfaces. I have tried fixing it but no luck. It is detecting the wall just fine but when switching surfaces it teleports a bit to the left or right than back.

https://gyazo.com/b1000c78b33bfad77944e3d780b3bd2f

local Player 		   = game.Players.LocalPlayer
local Character		   = Player.Character or Player.CharacterAdded:Wait()
local Humanoid   	   = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local hittingWall = false
local onWall 	  = false
local currentFace = nil

local climbVelocity = Instance.new("BodyVelocity")
climbVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
climbVelocity.Velocity = Vector3.new()
climbVelocity.P = 4000

local climbGyro = Instance.new("BodyGyro")
climbGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
climbGyro.CFrame = CFrame.new()
climbGyro.P = 4000

local climbParams = RaycastParams.new()
climbParams.FilterType = Enum.RaycastFilterType.Blacklist
climbParams.IgnoreWater = true
climbParams.FilterDescendantsInstances = {Character}

local UserInputService = game:GetService("UserInputService")
local RunService 	   = game:GetService("RunService")
local TweenService     = game:GetService("TweenService")

local Controls = {Up = 0, Down = 0, Left = 0, Right = 0}

local leftCast  = false
local rightCast = false

function isKeyDown(Key)
	return UserInputService:IsKeyDown(Enum.KeyCode[Key])
end

local Speed = 8

function Climb()
	if hittingWall then
		
		HumanoidRootPart.Velocity = Vector3.new(0,0,0)
		
		if onWall then
			
			climbVelocity.Velocity = HumanoidRootPart.CFrame.LookVector * 0	 + Vector3.new(0,8,0)
			
			
		end
		
	end
end

function climbOff()
	climbVelocity.Parent = nil
	climbGyro.Parent = nil
	hittingWall = false
	onWall = false
	Humanoid.PlatformStand = false
	Humanoid.AutoRotate = true
	currentFace = nil
end

UserInputService.InputBegan:Connect(function(input, GPE)
	if input.KeyCode and not GPE then
		if input.KeyCode == Enum.KeyCode.Z then
			
			local rootOrigin = HumanoidRootPart.Position
			local rootDirection = HumanoidRootPart.CFrame.LookVector

			local rayResult = workspace:Raycast(rootOrigin, rootDirection, climbParams)
			
			if rayResult then
				
				currentFace = CFrame.new(rayResult.Position + rayResult.Normal, rayResult.Position)
				
				HumanoidRootPart.CFrame = CFrame.new(HumanoidRootPart.CFrame.Position, Vector3.new(HumanoidRootPart.Position.X - rayResult.Normal.X, HumanoidRootPart.Position.Y, HumanoidRootPart.Position.Z - rayResult.Normal.Z))
				climbGyro.CFrame = currentFace or CFrame.new()
				
				climbVelocity.Parent = HumanoidRootPart
				climbGyro.Parent = HumanoidRootPart
				
				Humanoid.AutoRotate = false
				Humanoid.PlatformStand = true
				
				hittingWall = true
				onWall = true
				
				repeat
					RunService.RenderStepped:Wait()				
					climbGyro.CFrame = currentFace or CFrame.new()
					--currentFace = CFrame.new(rayResult.Position + rayResult.Normal, rayResult.Position)
					
					if HumanoidRootPart.Position.Y >= ((rayResult.Instance.Position.Y + (rayResult.Instance.Size.Y / 2) ) + 3) and Humanoid.FloorMaterial == Enum.Material.Air then
						climbOff()
					end

					
					local Movement = HumanoidRootPart.CFrame:VectorToWorldSpace(Vector3.new(Controls.Left + Controls.Right, Controls.Up + Controls.Down, 0)) * Speed
					climbVelocity.Velocity = Movement
					
					local sideOriginRight = HumanoidRootPart.CFrame * CFrame.new(0, 0, -4).Position
					local sideDirectionRight = HumanoidRootPart.CFrame.RightVector * -4
					
					local sideResultRight = workspace:Raycast(sideOriginRight, sideDirectionRight, climbParams)
					
					if sideResultRight and (isKeyDown("D")) and not rightCast then 
						rightCast = true
						print(sideResultRight.Normal)
						HumanoidRootPart.CFrame = CFrame.new(sideResultRight.Position + sideResultRight.Normal, sideResultRight.Position)
						--TweenService:Create(HumanoidRootPart, TweenInfo.new(0.3), {CFrame = CFrame.new(HumanoidRootPart.CFrame.Position, Vector3.new(HumanoidRootPart.Position.X - sideResultRight.Normal.X, HumanoidRootPart.Position.Y, HumanoidRootPart.Position.Z - sideResultRight.Normal.Z))}):Play()
						currentFace = CFrame.new(sideResultRight.Position + sideResultRight.Normal, sideResultRight.Position)
						--wait(0.1)
						rightCast = false						
					end
					
					local sideOriginLeft = HumanoidRootPart.CFrame * CFrame.new(0, 0, -4).Position
					local sideDirectionLeft = HumanoidRootPart.CFrame.RightVector * 4

					local sideResultLeft = workspace:Raycast(sideOriginLeft, sideDirectionLeft, climbParams)

					if sideResultLeft and (isKeyDown("A")) and not leftCast then 
						leftCast = true
						print(sideResultLeft.Normal)
						HumanoidRootPart.CFrame = CFrame.new(sideResultLeft.Position+sideResultLeft.Normal, sideResultLeft.Position)
						--TweenService:Create(HumanoidRootPart, TweenInfo.new(0.4), {CFrame = CFrame.new(HumanoidRootPart.CFrame.Position, Vector3.new(HumanoidRootPart.Position.X - sideResultLeft.Normal.X, HumanoidRootPart.Position.Y, HumanoidRootPart.Position.Z - sideResultLeft.Normal.Z))}):Play()
						currentFace = CFrame.new(sideResultLeft.Position + sideResultLeft.Normal, sideResultLeft.Position)
						--wait(0.1)
						leftCast = false						
					end
					
				until hittingWall == false
				
			end
			
		end
	end
end)

UserInputService.InputBegan:Connect(function(input, GPE)
	if input.KeyCode and not GPE then
		if input.KeyCode == Enum.KeyCode.W then
			if onWall then
				Controls.Up = 1
			end
		elseif input.KeyCode == Enum.KeyCode.S then
			if onWall then
				Controls.Down = -1
			end
		elseif input.KeyCode == Enum.KeyCode.D then
			if onWall then
				Controls.Right = 1
			end
		elseif input.KeyCode == Enum.KeyCode.A then
			if onWall then
				Controls.Left = -1
			end
		end
	end	
end)

UserInputService.InputEnded:Connect(function(input, GPE)
	if input.KeyCode and not GPE then
		if input.KeyCode == Enum.KeyCode.W then
			if onWall then
				Controls.Up = 0
			end
		elseif input.KeyCode == Enum.KeyCode.S then
			if onWall then
				Controls.Down = 0
			end
		elseif input.KeyCode == Enum.KeyCode.D then
			if onWall then
				Controls.Right = 0
			end
		elseif input.KeyCode == Enum.KeyCode.A then
			if onWall then
				Controls.Left = 0
			end
		elseif input.KeyCode == Enum.KeyCode.Space and hittingWall then
			climbOff()
		end
	end	
end)
1 Like

After testing your script I figured that the “lag” comes from local sideOriginLeft = HumanoidRootPart.CFrame * CFrame.new(0, 0, -4).Position (same goes for the right side), and there’s less “lag” the closer -4 gets to 0 while also making it less reliable, i’m pretty bad on scripting but that’s all I managed to see that could cause it

(just realised the post is pretty old and you probably fixed the issue by now lol)