I redid a ledge grab system but an error is happening, so I came to ask for help. The entire script part of holding the ledge is working normally, the problem is the animation that instead of the player holding the ledge normally, it only activates once and then stops, causing this bug shown in the video below. Can someone please help me?
Script
--varibles--
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local GuiService = game:GetService("GuiService")
local player = game.Players.LocalPlayer
local character = player.Character
local camera = workspace.CurrentCamera
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local vaultMoveNumber = 10
local canVault = true
local canMove = true
local vaultConnection = nil
local ledgePart = nil
local grabAnim = humanoid:LoadAnimation(script:WaitForChild("Grab"))
local grabRightAnim = humanoid:LoadAnimation(script:WaitForChild("GrabRight"))
local grabLeftAnim = humanoid:LoadAnimation(script:WaitForChild("GrabLeft"))
--check--
local function partCheck(ledge)
local vaultPartCheck = workspace:Raycast(ledge.Position + Vector3.new(0, -1, 0) + ledge.LookVector * 1, ledge.UpVector * 3, raycastParams)
if vaultPartCheck == nil then
return true
else
return false
end
end
local function vaultMoveCheck(ray, anim)
local localPos = ray.Instance.CFrame:PointToObjectSpace(ray.Position)
local localLedgePos = Vector3.new(localPos.X, ray.Instance.Size.Y/2, localPos.Z)
local ledgePos = ray.Instance.CFrame:PointToWorldSpace(localLedgePos)
local ledgeOffset = CFrame.lookAt(ledgePos, ledgePos - ray.Normal)
if partCheck(ledgeOffset) then
local magnitude = (ledgePos - head.Position).Magnitude
if magnitude < 3 then
local info = TweenInfo.new(.15, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0, false, 0)
local goal = {CFrame = ledgeOffset + Vector3.new(0, -2, 0) + ledgeOffset.LookVector * -1}
local tween = TweenService:Create(ledgePart, info, goal)
tween:Play()
canMove = false
--Animation--
if anim == "Right" then
grabRightAnim:Play()
elseif anim == "Left" then
grabLeftAnim:Play()
end
--Delay--
task.delay(.35, function()
canMove = true
end)
end
end
end
--Movement--
local function vaultMove(direction, anim)
local moveRay = workspace:Raycast(head.CFrame.Position, head.CFrame.RightVector * direction + head.CFrame.LookVector * 8, raycastParams)
if moveRay then
if moveRay.Instance then
vaultMoveCheck(moveRay, anim)
end
else
local turnRay = workspace:Raycast(head.CFrame.Position + Vector3.new(0, -1, 0) + head.CFrame.RightVector * direction, head.CFrame.RightVector * -direction + head.CFrame.LookVector * 2, raycastParams)
if turnRay then
if turnRay.Instance then
vaultMoveCheck(turnRay, anim)
end
end
end
end
--Detect Direction--
humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
if (humanoid.MoveDirection:Dot(camera.CFrame.RightVector) > .7) and not canVault and canMove then
vaultMove(vaultMoveNumber, "Right")
end
if (humanoid.MoveDirection:Dot(-camera.CFrame.RightVector) > .7) and not canVault and canMove then
vaultMove(-vaultMoveNumber, "Left")
end
end)
--Detecting Ledges--
local function detectLedge()
if canVault and (humanoid:GetState() == Enum.HumanoidStateType.Freefall or humanoid:GetState() == Enum.HumanoidStateType.Jumping) then
local vaultCheck = workspace:Raycast(rootPart.CFrame.Position, rootPart.CFrame.LookVector * 5, raycastParams)
if vaultCheck then
if vaultCheck.Instance then
local localPos = vaultCheck.Instance.CFrame:PointToObjectSpace(vaultCheck.Position)
local localLedgePos = Vector3.new(localPos.X, vaultCheck.Instance.Size.Y/2, localPos.Z)
local ledgePos = vaultCheck.Instance.CFrame:PointToWorldSpace(localLedgePos)
local ledgeOffset = CFrame.lookAt(ledgePos, ledgePos - vaultCheck.Normal)
local magnitude = (ledgePos - head.Position).Magnitude
if magnitude < 4 then
if partCheck(ledgeOffset) then
canVault = false
--Movement--
ledgePart = Instance.new("Part")
ledgePart.Parent = workspace
ledgePart.Anchored = true
ledgePart.Size = Vector3.one
ledgePart.CFrame = ledgeOffset + Vector3.new(0, -2, 0) + ledgeOffset.LookVector * -1
ledgePart.CanQuery = false
ledgePart.CanCollide = false
ledgePart.CanTouch = false
ledgePart.Transparency = 1
--Animation--
grabAnim:Play()
--Connection--
vaultConnection = RunService.RenderStepped:Connect(function(dt)
rootPart.Anchored = true
humanoid.AutoRotate = false -- so shift lock doesnt't rotate character
rootPart.CFrame = rootPart.CFrame:Lerp(CFrame.lookAt(ledgePart.Position, (ledgePart.CFrame * CFrame.new(0, 0, -1)).Position), .25)
humanoid:ChangeState(Enum.HumanoidStateType.Seated)
end)
end
end
end
end
elseif not canVault then
canVault = true
humanoid.AutoRotate = true
rootPart.Anchored = false
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
grabAnim:Stop()
--Disconnect--
if vaultConnection then
vaultConnection:Disconnect()
end
if ledgePart then
ledgePart:Destroy()
end
end
end
--PC--
UserInputService.InputBegan:Connect(function(input, gp)
if (input.KeyCode == Enum.KeyCode.ButtonA or input.KeyCode == Enum.KeyCode.Space) then
detectLedge()
end
end)
--Mobile--
if UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled and not UserInputService.MouseEnabled and not UserInputService.GamepadEnabled and not GuiService:IsTenFootInterface() then
local jumpButton = player.PlayerGui:WaitForChild("TouchGui"):WaitForChild("TouchControlFrame"):WaitForChild("JumpButton")
jumpButton.Activated:Connect(function()
detectLedge()
end)
end
Video
The animation does not have the loop activated, because when it is activated, even when jumping back to the ground the animation continues.