Help with making parkour system smoother

I currently have a parkour system that I would like to make smoother. When grabbing onto ledges it snaps into place rather than smoothly positioning. I have tried tweens but they didn’t help very much.

-- Server code
local Events_And_Functions = game:GetService("ReplicatedStorage"):WaitForChild("Events/Funcions")
local ParkourEvents = Events_And_Functions:WaitForChild("Parkour")
local LedgeFunction = ParkourEvents:WaitForChild("GrabLedge")
local GrabPartName = "GrabPart"

function ClosestLedge(Character)
	local Ledges = {}
	local Root = Character.HumanoidRootPart.Position
	local Closest = nil
	
	for _,v in pairs(workspace:GetDescendants()) do
		if v.Name == "GrabPartName" or v:FindFirstChild("IsLedge") then
			if Closest == nil then
				Closest = v
			else
				if (Root - v.Position).magnitude < (Closest.Position - Root).magnitude then
					Closest = v
				end
			end
		end
	end
	
	return Closest
end

function isInsideBrick(position, brick)
	local v3 = brick.CFrame:PointToObjectSpace(position)
	return (math.abs(v3.X) <= brick.Size.X / 2)
		and (math.abs(v3.Y) <= brick.Size.Y / 2)
		and (math.abs(v3.Z) <= brick.Size.Z / 2)
end

function GrabLedge(Player,Grab,Drop)
	local Character = Player.Character
	if Grab == true then
		local Ledge = ClosestLedge(Character)
		local raycastParams = RaycastParams.new()
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.FilterDescendantsInstances = {Character}
		raycastParams.IgnoreWater = true

		local Offset = Character.HumanoidRootPart.CFrame:ToObjectSpace(Ledge.CFrame)
		local Origin =  (Ledge.CFrame * CFrame.new(Offset.X,0,-Offset.Z)).Position
		local RayDirection = -(Character.HumanoidRootPart.CFrame * CFrame.new(0,Origin.Y,0)).LookVector * 3
		local raycastResult = workspace:Raycast(Origin, RayDirection, raycastParams)

		if raycastResult then
			local Distance = (raycastResult.Position - Character.Head.Position).Magnitude
			if Distance <= 3 then
				Character.Humanoid.PlatformStand = true
				Character.HumanoidRootPart.Anchored = true
				workspace.Part2.CFrame = CFrame.new(raycastResult.Position) * CFrame.new(0.02,0,0) * CFrame.Angles(0,math.rad(Ledge.Orientation.Y),0)
				Character.HumanoidRootPart.CFrame = (CFrame.new(raycastResult.Position) * CFrame.Angles(0,math.rad(Ledge.Orientation.Y)+math.rad(180),0)) * CFrame.new(0,-0.75,2.5)
				return true
			else
				return false
			end
		else
			return false
		end
	else
		Character.HumanoidRootPart.Anchored = false
		Character.Humanoid.PlatformStand = false
		wait()
		if not Drop then
			Character.HumanoidRootPart.Velocity = Vector3.new(0,50,0)
		end
	end
end

LedgeFunction.OnServerInvoke = GrabLedge
-- Client Code
local UIS = game:GetService("UserInputService")
local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Events_And_Functions = ReplicatedStorage:WaitForChild("Events/Funcions")
local AnimationsFolder = ReplicatedStorage:WaitForChild("Animations")
local GrabAnim = Character:WaitForChild("Humanoid"):LoadAnimation(AnimationsFolder.GrabAnim)
local ParkourEvents = Events_And_Functions:WaitForChild("Parkour")
local LedgeFunction = ParkourEvents:WaitForChild("GrabLedge")
local HoldingSpace = false
local GrabbingLedge = false
local GrabCooldown = false
local GrabCooldownTime = 0.3

function LetGoOfLedge(Grab,Drop)
	GrabCooldown = true
	GrabAnim:Stop()
	LedgeFunction:InvokeServer(Grab,Drop)
	GrabbingLedge = false
	wait(GrabCooldownTime)
	GrabCooldown = false
end

UIS.InputBegan:Connect(function(IO,GPE)
	if not GPE then
		if IO.KeyCode == Enum.KeyCode.Space then
			if not GrabbingLedge and not GrabCooldown then
				for i = 1,20 do
					wait(0.1)
					if UIS:IsKeyDown(Enum.KeyCode.Space) and LedgeFunction:InvokeServer(true) == true then
						GrabbingLedge = true
						GrabAnim:Play()
						return
					end
				end
			else
				LetGoOfLedge(false,false)
			end
		elseif IO.KeyCode == Enum.KeyCode.C then
			LetGoOfLedge(false,true)
		end
	end
end)

Any feedback is greatly appreciated!

3 Likes

I have two thoughts about this:

  1. Maybe some constraint could be used? (or align position?), that could make it smoother
  2. If nothing seems to make it smooth, could it be a Server v. Client lag? maybe doing some tweening (or any smoothing) client side could improve the appearance
2 Likes

That is because you are handling the player positions on the server, ping causing it to take a second for it to take effect.

6 Likes

Add a cooldown for a bit longer like 0.2 and add a animation like your grabbing on to something

1 Like