How can I attach player to ledge for ledge grab system?

Hello, I’m trying to make a ledge grabbing system and my current approach is to have 2 check parts one to detect when the player touches a wall wallCheckPart and another which detects if the player can actually grab the ledge when they jump ledgeCheckPart.

This approach seems like it will work fine the issue I have is how can I actually attach the player to the ledge, also how can I make my ledgeCheckPart follow the player, but attached to the wall?

-----------------------------------------------------------------------------
-- Variables
-----------------------------------------------------------------------------
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")
local ledgeCheckPart = nil
local connections = {}
local debounce = false
local WallCheckerComponent = Component.new {
	Tag = "WallChecker",
	Ancestors = {workspace}
}
WallCheckerComponent.GrabbedLedge = Signal.new()


-----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------- 
function WallCheckerComponent:CanReachLedge(object)
	ledgeCheckPart = Instance.new("Part")
	ledgeCheckPart.Anchored = true
	ledgeCheckPart.CanCollide = false
	ledgeCheckPart.Material = Enum.Material.ForceField
	ledgeCheckPart.Color = Color3.fromRGB(255, 255, 255)
	ledgeCheckPart.Transparency = 0
	ledgeCheckPart.Parent = workspace

	--To-Do: Make it follow the player, but have it be snapped to whatever wall they're near
	connections["MovePart"] = RunService.Stepped:Connect(function(dt)
		if ledgeCheckPart then
			local y = object.Position.Y + (object.Size.Y/2 + ledgeCheckPart.Size.Y/2)
			local x = head.Position.X
			local z = head.Position.Z
			ledgeCheckPart.Position = Vector3.new(x,y,z)			
		end
	end)

	-- Check if the player touched it (i.e: they're able to grab the ledge)
	connections["Touched"] = ledgeCheckPart.Touched:Connect(function(hit)
		if Players:GetPlayerFromCharacter(hit.Parent) then
			self.GrabbedLedge:Fire()
		end
	end)
end

-----------------------------------------------------------------------------
-- Events
-----------------------------------------------------------------------------
WallCheckerComponent.Started:Connect(function(component)
	local wallCheckPart = component.Instance
	
	wallCheckPart.Touched:Connect(function(hit)
		if not debounce and CollectionService:HasTag(hit,"Wall") then
			debounce = true
			wallCheckPart.Color = Color3.fromRGB(170, 0, 0)			
			WallCheckerComponent:CanReachLedge(hit)
		end
	end)
	
	wallCheckPart.TouchEnded:Connect(function()
		if debounce then
			debounce = false
			wallCheckPart.Color = Color3.fromRGB(255, 255, 255)
			ledgeCheckPart:Destroy()
			ledgeCheckPart = nil
			connections["MovePart"]:Disconnect()
			connections["Touched"]:Disconnect()
		end
	end)
end)

-- (in PlayerController code)
-- listens for event
WCComponent.GrabbedLedge:Connect(function()
	if not state:is("ledgegrab") then
		state:ledgegrab()
	end
end)

Quick video demonstrating what the code does.

3 Likes