Code review and better ways to create climb system?

  • What does the code do and what are you not satisfied with?
    Hello! This is a climbing script me and a friend made for a GameJam, and I was wondering if there were any better ways to create a climbing system or any ways to change the way the code functions.

Currently, the code works well, however the starting climb initialization is sort of buggy, the video showcases this below.


as you can see (around 15 sec), the starting climb kind of is bugged, and i believe it has something to do with the task.wait() inside the start climbing function.

  • What potential improvements have you considered?
    i’ve considered removing this cooldown, however that allows the players to sort of spam the climb button, which wouldn’t fit the style of the game
  • How (specifically) do you want to improve the code?
    I would like to clean things up with the help of the forum and fix this imperfection

scripts down below, ty ^^

climb initializer
--Vars
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")
local humanoidRootPart = char:WaitForChild("HumanoidRootPart")
local userInputService = game:GetService("UserInputService")
local runService = game:GetService("RunService")
local head = char:WaitForChild("Head")

--Extra Vars

local wallClimbing = false
local climbingSpeed = 3000
local keyToClimb = Enum.KeyCode.E
local climbDirection = Vector3.new(0, 0, 0)
local pressWait = false

-- velocity
local bodyVelocity = Instance.new("LinearVelocity")
bodyVelocity.MaxForce = 4000000
bodyVelocity.VectorVelocity = Vector3.new(0,0,0)
bodyVelocity.Parent = head

--Anims
local climbAnimation = Instance.new("Animation")
climbAnimation.AnimationId = "rbxassetid://95035375294805"
local climbingAnimTrack = humanoid:LoadAnimation(climbAnimation)

local function isNearWall()

return require(script.ClimbHandler).WallCheck()
end


local function startClimbing()
	wallClimbing = true
	workspace.Gravity = 45
	humanoid.PlatformStand = true
	climbingAnimTrack:Play()  
	task.wait(0.6)
	print("release")
	bodyVelocity.Parent = head
	humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
	
end


local function stopClimbing()
	wallClimbing = false
	humanoid.PlatformStand = false
	humanoid:ChangeState(Enum.HumanoidStateType.GettingUp)
	bodyVelocity.Parent = nil
	climbingAnimTrack:Stop() 
end


local function ClimbingUpd()
	if wallClimbing then
		if userInputService:IsKeyDown(Enum.KeyCode.Space) then

			bodyVelocity.VectorVelocity= Vector3.new(0, climbingSpeed, 0)
			
		elseif userInputService:IsKeyDown(Enum.KeyCode.LeftShift) then

			bodyVelocity.VectorVelocity = Vector3.new(0, -climbingSpeed, 0)
		else

			bodyVelocity.VectorVelocity = Vector3.new(0, 0, 0)
		end
	end
end


runService.Heartbeat:Connect(function()

	if isNearWall() and userInputService:IsKeyDown(keyToClimb) then
		
		if not wallClimbing then
			startClimbing()
		end
	elseif not isNearWall() or not userInputService:IsKeyDown(keyToClimb) then
		if wallClimbing then
			stopClimbing()
			workspace.Gravity = 196
		end
	end
end)
climb handler (module script)

local humanoidRootPart = script.Parent.Parent:WaitForChild(“HumanoidRootPart”)
local char = humanoidRootPart.Parent
local module = {}

function module.WallCheck()
local ray = Ray.new(humanoidRootPart.Position, humanoidRootPart.CFrame.LookVector * 2)
local hit, position = workspace:FindPartOnRay(ray, char)

if hit then

	local Climbable = hit:GetAttribute("Climbable")
	if Climbable == true then
	--	print(Climbable)
		return true and hit and hit:IsA("Part") and not hit:IsDescendantOf(char)
	else
	--	print("not climbable part")
	end

end

end

return module

system summary: each heartbeat, the client script runs the module script function WallCheck and gets the values returned to it. if they are true, then the player can start climbing. the WallCheck function uses raycasting to check if the player is close to a part and if it has the attribute “Climbable” set to true