Hello, I want my wall grab script to grab onto a surface and stay in the correct orientation based on where the player grabbed it. I got this to work however when spinning around a circle, when reaching either the top or bottom of it my character would always turn 180 which looked unnatural. I think it might be because of gimbal lock but I’m not sure how to prevent that.
This is the part that controls the Character’s orientation and position.
local targetLookAt = CFrame.lookAt(ledgePart.Position, (ledgePart.CFrame * CFrame.new(0, 0, -1)).Position)
rootPart.CFrame = rootPart.CFrame:Lerp(targetLookAt, 1)
This is the whole function.
local function detectLedge()
print("Function started")
if vaultsleft > 0 and 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)
local AboveHeadCheck = workspace:Raycast(head.CFrame.Position, rootPart.CFrame.LookVector * 5, raycastParams)
local headoverledge = false
StopVault = false
if not AboveHeadCheck then
headoverledge = true
end
if vaultCheck then
if vaultCheck.Instance then
local localPos = vaultCheck.Instance.CFrame:PointToObjectSpace(vaultCheck.Position)
local yOffset
local ledgePosition
if not headoverledge then
yOffset = 0
ledgePosition = vaultCheck.Position + vaultCheck.Normal * 1 + Vector3.new(0, yOffset, 0)
else
yOffset = (vaultCheck.Instance.Size.Y / 2 - 2)
local adjustedLocalPos = Vector3.new(localPos.X, yOffset, localPos.Z)
ledgePosition = vaultCheck.Instance.CFrame:PointToWorldSpace(adjustedLocalPos) + vaultCheck.Normal * 1
end
local targetPos = ledgePosition - vaultCheck.Normal
local magnitude = (ledgePosition - head.Position).Magnitude
if magnitude < 5 then
local dotProduct = rootPart.CFrame.LookVector:Dot(vaultCheck.Normal)
if dotProduct > -0.9 then
return
end
vaultsleft -= 1 -- START VAULT
character:SetAttribute("WallGrab", true)
AniTrack:play()
canVault = false
ledgePart = Instance.new("Part")
ledgePart.Parent = workspace
ledgePart.Size = Vector3.one
ledgePart.CFrame = CFrame.lookAt(ledgePosition, targetPos)
ledgePart.CanQuery = false
ledgePart.CanCollide = false
ledgePart.CanTouch = false
ledgePart.Transparency = 0
local weldTarget = vaultCheck.Instance
if weldTarget and weldTarget:IsA("BasePart") then
local weld = Instance.new("WeldConstraint")
weld.Part0 = ledgePart
weld.Part1 = weldTarget
weld.Parent = ledgePart
end
local starttime = tick()
vaultConnection = RunService.RenderStepped:Connect(function(dt)
local dotProduct = rootPart.CFrame.LookVector:Dot(vaultCheck.Normal)
if tick() - starttime > 1000 or holdingS == true or CancelFlag == true then
StopVault = true
end
if StopVault then
print("Stopped")
vaultConnection:Disconnect()
canVault = true
character:SetAttribute("WallGrab", false)
AniTrack:Stop()
rootPart.Anchored = false
character:SetAttribute("CanRotate", true)
if ledgePart then
ledgePart:Destroy()
end
else
rootPart.AssemblyLinearVelocity = Vector3.new(0, 0, 0)
rootPart.Anchored = true
character:SetAttribute("CanRotate", false)
local targetLookAt = CFrame.lookAt(ledgePart.Position, (ledgePart.CFrame * CFrame.new(0, 0, -1)).Position)
rootPart.CFrame = rootPart.CFrame:Lerp(targetLookAt, 1)
humanoid:ChangeState(Enum.HumanoidStateType.Seated)
end
end)
end
end
end
elseif canVault == false then
canVault = true
character:SetAttribute("WallGrab", false)
AniTrack:Stop()
character:SetAttribute("CanRotate", true)
rootPart.Anchored = false
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
--check if it exists and then disconnect
if vaultConnection then
vaultConnection:Disconnect()
end
if ledgePart then
ledgePart:Destroy()
end
end
end