Grapple Hook random forces issues

  1. What do you want to achieve?
    I want to achive a system that doesn’t fling me around when I am using my grappler.

  2. What is the issue?
    I’m encountering an issue with my grappler where the player gets flung around uncontrollably. This happens because I’m setting the player’s rotation to a fixed Z and X rotation, while the Y rotation is set to match where the player is looking, similar to Shiftlock. However, this results in random forces being applied to the player for some reason.

I need to keep the applied rotation, so removing it isn’t an option. The reason I set the rotation in the first place is that when the player is in the physics state, they’re free to rotate. To prevent this, I set the rotation to keep the player upright, but this causes the flinging issue.
And also, the flinging gets extra intense when I am holding a tool while grappling. But it still happends when I don’t hold another tool just not as much, so the issue is not when I am holding a tool.

In the video, I don’t get flung around when not holding a tool but still setting the players rotation. That is because it only happends sometimes is very unrecognisable. And I couldn’t catch a moment when it happend. But it happends very little some times.

Grappler Script, only server because client isn't so relevant here
local grapplerRemote = script.Parent.grapplerEvent
local grapplerAttachedSound = game.SoundService.WeaponSounds.grappleConnected

function createGrapplerRope(mousePos, mouseTarget, humanoidRootPart, lenght)
	local attachment0 = Instance.new("Attachment")
	attachment0.Name = "grapplerBodyAttachment"
	attachment0.Position = Vector3.new(0, 0, 0)
	attachment0.Orientation = Vector3.new(0, 90, 0)
	attachment0.Parent = humanoidRootPart

	local attachment1 = Instance.new("Attachment")
	attachment1.Name = "grapplerTargetAttachment"
	attachment1.Position = mouseTarget.CFrame:PointToObjectSpace(mousePos.Position)
	attachment1.Parent = mouseTarget

	local referenceToAttachment2 = Instance.new("ObjectValue")
	referenceToAttachment2.Name = "referenceToGrapplerTargetAttachment"
	referenceToAttachment2.Value = attachment1
	referenceToAttachment2.Parent = humanoidRootPart

	local ropeConstraint = Instance.new("RopeConstraint")
	ropeConstraint.Name = "grapplerRope"
	ropeConstraint.Thickness = 0.2
	ropeConstraint.Length = lenght
	ropeConstraint.Color = BrickColor.Black()
	ropeConstraint.Attachment0 = attachment0
	ropeConstraint.Attachment1 = attachment1
	ropeConstraint.Visible = true
	ropeConstraint.Parent = humanoidRootPart
	
	local grapplerConnectedSound = grapplerAttachedSound:Clone()
	grapplerConnectedSound.Parent = humanoidRootPart
	grapplerConnectedSound.Playing = true
end

function removeGrapplerRope(humanoidRootPart)
	local referenceToAttachment2 = humanoidRootPart:FindFirstChild("referenceToGrapplerTargetAttachment")
	local ropeConstraint = humanoidRootPart:FindFirstChild("grapplerRope")
	
	local attachment0 = humanoidRootPart:FindFirstChild("grapplerBodyAttachment")
	local attachment1 = referenceToAttachment2.Value
	
	local grapplerConnectedSound = humanoidRootPart:FindFirstChild("grappleConnected")

	attachment0:Destroy()
	attachment1:Destroy()
	ropeConstraint:Destroy()
	referenceToAttachment2:Destroy()
	grapplerConnectedSound:Destroy()
end

function addGrapplerBelt(humanoidRootPart)
	local grapplerBelt = game.ReplicatedStorage.grapplerBelt:Clone()
	grapplerBelt.Parent = humanoidRootPart

	local weld = Instance.new("Weld")
	weld.Part0 = humanoidRootPart
	weld.Part1 = grapplerBelt
	weld.C0 = CFrame.new(0, -0.75, 0)
	weld.Parent = grapplerBelt
end

function removeGrapplerBelt(humanoidRootPart)
	local grapplerBelt = humanoidRootPart:FindFirstChild("grapplerBelt")
	grapplerBelt:Destroy()
end

grapplerRemote.OnServerEvent:Connect(function(player, action, mouseTarget, mousePos, lenght)
	local character = player.Character or player.CharacterAdded:Wait()
	local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

	if action == "grappleStarted" then
		createGrapplerRope(mousePos, mouseTarget, humanoidRootPart, lenght)
	elseif action == "grappleEnded" then
		removeGrapplerRope(humanoidRootPart)
	end

	if action == "grapplerEquiped" then
		addGrapplerBelt(humanoidRootPart)
	elseif action == "grapplerUnequiped" then
		removeGrapplerBelt(humanoidRootPart)
	end
end)
Set Rotation Script

Here is the script that sets the rotation of the player, the parts of the script that actaully sets the rotation is the second two last lines of code:

-- Variables
local uis = game:GetService("UserInputService")
local runService = game:GetService("RunService")

local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local character = player.Character or player.CharacterAdded:Wait()

local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")

local lastState = false
local loadingCompleted = false
local debounce = true

-- GUI
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
game.Workspace.Camera.FieldOfView = 90

--New Movement Sounds
humanoidRootPart:WaitForChild("Jumping").SoundId = game.SoundService.playerSounds.jumpSound.SoundId
humanoidRootPart:WaitForChild("Running").SoundId = game.SoundService.playerSounds.walkSound.SoundId

--Movement Sound Properties
humanoidRootPart:WaitForChild("Jumping").Volume = 0.5
humanoidRootPart:WaitForChild("Running").Volume = 2

humanoidRootPart:WaitForChild("Jumping").PlaybackSpeed = 1
humanoidRootPart:WaitForChild("Running").PlaybackSpeed = 1

-- Mouse Icon
player:GetMouse().Icon = "http://www.roblox.com/asset/?id=18663286339"

local function isInFirstPerson()
	if character.Head.LocalTransparencyModifier == 1 then
		return true
	else
		return false
	end
end

local function updateRotation()
	if humanoidRootPart then
		local cameraDirection = camera.CFrame.LookVector
		local newCFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + Vector3.new(cameraDirection.X, 0, cameraDirection.Z))
		humanoidRootPart.CFrame = newCFrame
	end
end

for i, v in pairs(character:GetChildren()) do
	if v:IsA("BasePart") and v.Name ~= "Head" and v.Name ~= "Torso" then
		v.LocalTransparencyModifier = v.Transparency
		v.Changed:Connect(function(property)
			v.LocalTransparencyModifier = v.Transparency
		end)
	end
end

runService.Heartbeat:Connect(function()
	humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
	
	-- Crosshair if weapon is equiped
	for _, item in pairs(character:GetChildren()) do
		if item:IsA("Tool") then
			if item:FindFirstChild("IsAWeapon") then
				player:GetMouse().Icon = "http://www.roblox.com/asset/?id=17787998274"
				debounce = false
			else
				if not debounce then
					player:GetMouse().Icon = "http://www.roblox.com/asset/?id=18663286339"
					debounce = true
				end
			end
		else
			if not debounce then
				player:GetMouse().Icon = "http://www.roblox.com/asset/?id=18663286339"
				debounce = true
			end
		end
	end
	
	-- Look in camera direction
	local lookDirection = game.Workspace.CurrentCamera.CFrame.LookVector
	humanoidRootPart.CFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + Vector3.new(lookDirection.X, 0, lookDirection.Z))
end)
Videos

With setting rotation
With setting rotation - Clipped with Medal.tv

Without setting rotation
Without setting rotation - Clipped with Medal.tv

Any help super appreciated! :smile:

EDIT:
I didn’t think there was anything important to show in the client script at first, but I realized I forgot to mention that I set the physics state of the humanoid there. Besides that, the client script mainly just sends the keys I press to the server, which is already handled. And yes, the state does change—I’ve checked the code and tested it. So the physics state is already being applied to the player.

I tried setting all the tools to massless, and it made a HUGE difference! The random forces are now almost completely gone. There are still some very, very small forces being applied though, but tbh, they don’t bother me to much. It would be awesome to have them fully gone though! So the issue is not resolved yet.

EDIT AGAIN:
It got solved by an amazing guy on reddit, use bodygyro or align orientation instead of just setting the CFrame on the players rotation.

1 Like

Solved by setting the rotation of the player with a bodygyro or align orientation. Instead of just setting the rotation directly with CFrame.new()

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.