Need help with this Torso Movement Script

Hello people from Forum. I want help on a script. The script works just fine. It’s a script where it moves your torso, following your camera’s movement. The problem is that when you look too high with your camera it ‘glitches’, but only when theres some part or something. But when I’m looking at the sky, nothing happens, it works just fine. I think It’s just a small mistake in the script that makes that happen.
By the way, it’s a Local Script located in StarterCharacterScripts.
This topic isn’t such an issue, but I would be very glad if someone solved it for me!

1. What do you want to achieve?

I want to achieve something that moves your torso in the camera’s direction, so the flashlight follows the movement too.
Here’s a video showing an example:

2. What is the issue?

The issue of this script is that the camera glitches when you’re looking up, but only when there’s a part or something. But when there’s nothing, like looking at the sky, everything’s ok and the camera doesn’t glitch.
I also don’t understand why when I record it doesn’t show the glitch that well, which makes me even more confused. I’ve tried other Forums to help me, but they couldn’t. Is it because of my GPU (computer in general), Roblox’s fault or is it the script that’s not built well?
Here’s the issue:

3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I’ve tried using ChatGPT since I was clueless of what was wrong. It made it worse…
Tried other Forums nothing changed.
So I’m here to see if anyone can actually help me.
And no I didn’t look for solutions on the Developer Hub since my script is unique and there’s nothing related to this topic.

Here’s the script. It’s a local script located in StarterCharacterScripts:

wait()

--[Pre-Funcs]:

local Ang = CFrame.Angles	--[Storing these as variables so I dont have to type them out.]
local aSin = math.asin
local aTan = math.atan

--[Constants]:

local Cam = game.Workspace.CurrentCamera

local Plr = game.Players.LocalPlayer
local Mouse = Plr:GetMouse()
local Body = Plr.Character or Plr.CharacterAdded:wait()
local Head = Body:WaitForChild("Head")
local Hum = Body:WaitForChild("Humanoid")
local Core = Body:WaitForChild("HumanoidRootPart")
local IsR6 = (Hum.RigType.Value==0)	--[Checking if the player is using R15 or R6.]
local Trso = (IsR6 and Body:WaitForChild("Torso")) or Body:WaitForChild("UpperTorso")
local Neck = (IsR6 and Trso:WaitForChild("Neck")) or Head:WaitForChild("Neck")	--[Once we know the Rig, we know what to find.]
local Waist = (not IsR6 and Trso:WaitForChild("Waist"))	--[R6 doesn't have a waist joint, unfortunately.]

--[[
	[Whether rotation follows the camera or the mouse.]
	[Useful with tools if true, but camera tracking runs smoother.]
--]]
local MseGuide = true
--[[
	[Whether the whole character turns to face the mouse.]
	[If set to true, MseGuide will be set to true and both HeadHorFactor and BodyHorFactor will be set to 0]
--]]
local TurnCharacterToMouse = true
--[[
	[Horizontal and Vertical limits for head and body tracking.]
	[Setting to 0 negates tracking, setting to 1 is normal tracking, and setting to anything higher than 1 goes past real life head/body rotation capabilities.]
--]]
local HeadHorFactor = 1
local HeadVertFactor = 1
local BodyHorFactor = 1.5
local BodyVertFactor = 1.4

--[[
	[How fast the body rotates.]
	[Setting to 0 negates tracking, and setting to 1 is instant rotation. 0.5 is a nice in-between that works with MseGuide on or off.]
	[Setting this any higher than 1 causes weird glitchy shaking occasionally.]
--]]
local UpdateSpeed = 0.5

local NeckOrgnC0 = Neck.C0	--[Get the base C0 to manipulate off of.]
local WaistOrgnC0 = (not IsR6 and Waist.C0)	--[Get the base C0 to manipulate off of.]

--[Setup]:

Neck.MaxVelocity = 1/3

-- Activation]:
if TurnCharacterToMouse == true then
	MseGuide = true
	HeadHorFactor = 0
	BodyHorFactor = 0
end

game:GetService("RunService").RenderStepped:Connect(function()
	if game:GetService("UserInputService").MouseEnabled then
		local CamCF = Cam.CoordinateFrame
		if ((IsR6 and Body["Torso"]) or Body["UpperTorso"])~=nil and Body["Head"]~=nil then	--[Check for the Torso and Head...]
			local TrsoLV = Trso.CFrame.lookVector
			local HdPos = Head.CFrame.p
			if IsR6 and Neck or Neck and Waist then	--[Make sure the Neck still exists.]
				if Cam.CameraSubject:IsDescendantOf(Body) or Cam.CameraSubject:IsDescendantOf(Plr) then
					local Dist = nil;
					local Diff = nil;
					if not MseGuide then	--[If not tracking the Mouse then get the Camera.]
						Dist = (Head.CFrame.p-CamCF.p).magnitude
						Diff = Head.CFrame.Y-CamCF.Y
						if not IsR6 then	--[R6 and R15 Neck rotation C0s are different; R15: X axis inverted and Z is now the Y.]
							Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang((aSin(Diff/Dist)*HeadVertFactor), -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor, 0), UpdateSpeed/2)
							Waist.C0 = Waist.C0:lerp(WaistOrgnC0*Ang((aSin(Diff/Dist)*BodyVertFactor), -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*BodyHorFactor, 0), UpdateSpeed/2)
						else	--[R15s actually have the properly oriented Neck CFrame.]
							Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang(-(aSin(Diff/Dist)*HeadVertFactor), 0, -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor),UpdateSpeed/2)
						end
					else
						local Point = Mouse.Hit.p
						Dist = (Head.CFrame.p-Point).magnitude
						Diff = Head.CFrame.Y-Point.Y
						if not IsR6 then
							Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang(-(aTan(Diff/Dist)*HeadVertFactor), (((HdPos-Point).Unit):Cross(TrsoLV)).Y*HeadHorFactor, 0), UpdateSpeed/2)
							Waist.C0 = Waist.C0:lerp(WaistOrgnC0*Ang(-(aTan(Diff/Dist)*BodyVertFactor), (((HdPos-Point).Unit):Cross(TrsoLV)).Y*BodyHorFactor, 0), UpdateSpeed/2)
						else
							Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang((aTan(Diff/Dist)*HeadVertFactor), 0, (((HdPos-Point).Unit):Cross(TrsoLV)).Y*HeadHorFactor), UpdateSpeed/2)
						end
					end
				end
			end
		end
		if TurnCharacterToMouse == true then
			Hum.AutoRotate = false
			Core.CFrame = Core.CFrame:lerp(CFrame.new(Core.Position, Vector3.new(Mouse.Hit.p.x, Core.Position.Y, Mouse.Hit.p.z)), UpdateSpeed / 2)
		else
			Hum.AutoRotate = true
		end
	end
end)

game.ReplicatedStorage.Look.OnClientEvent:Connect(function(otherPlayer, neckCFrame, WaistCFrame)
	local Neck = otherPlayer.Character:FindFirstChild("Neck", true)
	local Waist = otherPlayer.Character:FindFirstChild("Waist", true)

	if Neck and Waist then
		game:GetService('TweenService'):Create(Neck, TweenInfo.new(.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 0, false, 0), {C0 = neckCFrame}):Play()
		game:GetService('TweenService'):Create(Waist, TweenInfo.new(.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 0, false, 0), {C0 = WaistCFrame}):Play()
	end
end)

while wait(0.0001) do
	game.ReplicatedStorage.Look:FireServer(Neck.C0, Waist.C0)
end

Here’s the server script located in ServerScriptService, but I think that this one isn’t the problem at all, but I will still provide it since I want help…:

game.ReplicatedStorage.Look.OnServerEvent:Connect(function(player, neckCFrame, WaistCFrame, mouseenabled)
	if mouseenabled then
		for key, value in pairs(game.Players:GetChildren()) do
			if value ~= player and (value.Character.Head.Position - player.Character.Head.Position).Magnitude < 10 then
				game.ReplicatedStorage.Look:FireClient(value, player, neckCFrame, WaistCFrame)
			end
		end
	end
end)

If you want to help me, you don’t need to write entire scripts or design entire systems for me, but rather tell me the part that’s wrong and make the changes. I don’t want to make your ‘work’ hard.

I believe your torso is colliding with parts around it causing the body + camera to move

I think so too…
But how can I solve this so the camera can be smoother and not glitch?
Is there any way?

set torso can collide to false or use collision groups.
Humanoid objects constantly sets the torso collision so you’ll have to put it inside a RunService.Heartbeat event if you don’t want to use collision groups

I’m using R15.
I’ve tried setting CanCollide off to HumanoidRootPart, UpperTorso and LowerTorso.
And instead of RenderStepped I used Heartbeat

But it did nothing.
I think the problem is with the CFrames or Positions/angles.
Through the script, is it possible to limit how much you can look up? Like the angle?

use IKControls, not any of this. the page linked has all the documentation you need, ive done this for a few games, takes only 20 minutes to code and its only like 50 lines shared between the client and server. does require physical setup in the player rig though. just follow the documentation and ensure your IK is on the server, not the client.

Ok! I will check this out. I will mark as solution if it works!

cool, reply if you need any help that the documentation fails at. trust me on that this is the method though

take this too actually, forgot this link

In my case, the flashlight (and other future tools) are/is on the right arm. Instead of LeftArm and LeftUpperArm do I put right?

yeah pretty much

IK stands for Inverse Kinematics, the algorithm that figures out how to rotate and position joints given a goal. it does this via the physics, so there is collisions and it looks natural. roblox has it so it works automatically on default r15 rigs, though applying some constraints ensures characters dont turn their head around like an owl, for example.

it functions through the Motor6ds in the player – same ones that animate the player, aka the “joints”.
youd make an IK from the server and make the chain root the torso motor6d and then the head (neck) join the endaffector. from there, add another IKControl for the arm. make both of the ik’s goal an attachment thats located at the position of the mouse in world space, or at least relative to the player’s character. the IK has a few properties that affect its solver to aid the effect you want, like LookAt, Transform, Rotate and Position.

for replication, pass the mouse position to the ik script which’ll update the IKControl.Target to the new position.

The attachment or the IKControl?

IKControl.Target takes an attachment or basepart, so you gotta make an attachment, parent it to Mouse.Target or the character themselves, and then update the passed WorldPosition (mouse.Hit.Position) from your client.

I made a new version of my code. And now it works! But the arm looks too smooth and the arm is more ‘up’ than the camera itself is (mouse hit position), if you know what I mean…

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

local upperArm = character:WaitForChild("RightUpperArm")
local hand = character:WaitForChild("RightHand")

local targetPart = Instance.new("Part")
targetPart.Name = "IKTarget"
targetPart.Anchored = true
targetPart.CanCollide = false
targetPart.Size = Vector3.new(0.2, 0.2, 0.2)
targetPart.Transparency = 1
targetPart.Parent = workspace

local attachment = Instance.new("Attachment")
attachment.Parent = targetPart

local ik = Instance.new("IKControl")
ik.Name = "ArmIK"
ik.Type = Enum.IKControlType.Position
ik.EndEffector = hand
ik.ChainRoot = upperArm
ik.Target = attachment
ik.Weight = 1
ik.Parent = humanoid
ik.Enabled = false

local function hasToolEquipped()
	for _, item in ipairs(character:GetChildren()) do
		if item:IsA("Tool") then
			return true
		end
	end
	return false
end

RunService.RenderStepped:Connect(function()
	if hasToolEquipped() then
		ik.Enabled = true

		local cam = workspace.CurrentCamera
		local direction = cam.CFrame.LookVector
		local position = hand.Position + direction * 3 + Vector3.new(0, 2, 0) -- forward & upward
		targetPart.Position = position
	else
		ik.Enabled = false
	end
end)

I tried using TweenService, but it was a little too smooth.
And I changed the positions.
Now it works! Thank you so much for reminding me about IKControl!
I will mark your response as solution now

RunService.RenderStepped:Connect(function()
	if hasToolEquipped() then
		ik.Enabled = true

		local cam = workspace.CurrentCamera
		local direction = cam.CFrame.LookVector
		local targetPos = hand.Position + direction * 2 + Vector3.new(0, 0.2, 0)

		--local tween = TweenService:Create(targetPart, tweenInfo, {Position = targetPos})
		--tween:Play()
		targetPart.Position = targetPos
	else
		ik.Enabled = false
	end
end)