How can I rotate a tool around the torso without it shifting position?

I’m making a gun system and I weld the guns to the torso. I want to make it so that when you look up and down the gun and hands and head go with it. It all works except for the fact that the gun becomes slightly offset. I want the gun to remain in the same exact relative location to the arms at all times and I am not sure how to do this as I am terrible at geometry. If there is a formula or script or anything I can take a look at please help me out.

I can’t use the C1 property on the tool as it offsets animations so it has to be the position and rotation of the C0 property.

My code:

local stance = self:GetHumanoidState("Stance")
	local itemData, item = self:GetCurrentItemData()

	local baseNeckCFrame:CFrame = self.BaseNeck
	local baseRightShoulderCFrame:CFrame = self.BaseRightShoulder
	local baseLeftShoulderCFrame:CFrame = self.BaseLeftShoulder

	local neckOffset = self:GetHumanoidState("N") or CFrame.identity
	local rightShoulderOffset = self:GetHumanoidState("RS") or CFrame.identity
	local leftShoulderOffset = self:GetHumanoidState("LS") or CFrame.identity

	if stance == Stances.Proning then
		local rightFlip = CFrame.Angles(math.rad(0), math.rad(0), math.rad(90))
		local leftFlip = CFrame.Angles(math.rad(0), math.rad(0), math.rad(-90))
		local neckFlip = CFrame.Angles(math.rad(-90), math.rad(0), math.rad(0))

		neckOffset *= neckFlip
		rightShoulderOffset *= rightFlip
		leftShoulderOffset *= leftFlip
	end

	local value = 0

	if itemData and itemData.RightArmMovement then
		value = 1
	end

	rightShoulderOffset = CFrame.identity:Lerp(rightShoulderOffset, value)
	leftShoulderOffset = CFrame.identity:Lerp(leftShoulderOffset, value)

	local neckCFrame:CFrame = baseNeckCFrame * neckOffset
	local rightShoulderCFrame:CFrame = baseRightShoulderCFrame * rightShoulderOffset
	local leftShoulderCFrame:CFrame = baseLeftShoulderCFrame * leftShoulderOffset

	if itemData and item then
		local baseTool6DC0CFrame:CFrame = itemData.GripC0 or CFrame.identity
		local baseTool6DC1CFrame:CFrame = itemData.GripC1 or CFrame.identity

		local tool6D:Motor6D? = self.Character:FindFirstChild("Tool6D", true)

		if tool6D then
			local rX, rY, rZ = neckOffset:ToOrientation()

			local rotation = CFrame.Angles(-rX, 0, 0)

			local degreesRotation = math.deg(rX)
			local value = degreesRotation / 90

			local tool6DCFrame = rotation 
			
			if workspace.Value.Value then
				tool6D.C0 = rotation
			end
		end
	end
	
	self.Neck.C0 = neckCFrame
	self.RightShoulder.C0 = rightShoulderCFrame
	self.LeftShoulder.C0 = leftShoulderCFrame

Video of issue:

I’m stuck here, please help me out. Thanks

1 Like

I’m still having this issue, I got reference points when looking up and down and lerping based on the percentage of how far up/down you’re looking and it kind of works but the in between values (45 degrees) offset slightly, if anyone could point me to some math formula that I could use please help.

I have no experience in first person gun mechanics whatsoever. But why not just set the right arm be the parent of the gun? The gun will stay in place at the spot you want it to be, it’ll stick to the arm at the same position no matter what. I think it’d work because the arm is working as you want it to already. I dunno, that’s just my idea.

That couldn’t work because the animations were made to be welded to the torso and also I decided to weld it to the torso so the gun’s position wouldn’t change when the arms position changed, but I found a solution finally. I feel dumb now but I’ll explain it in case anyone needs this for help or something:

(keep in mind you’re responsible for applying this to your own game, and a lot of the code is specific to my game)

function Object:UpdateMotors()
	local stance = self:GetHumanoidState("Stance")
	local itemData, item = self:GetCurrentItemData()

	local baseNeckCFrame:CFrame = self.BaseNeck
	local baseRightShoulderCFrame:CFrame = self.BaseRightShoulder
	local baseLeftShoulderCFrame:CFrame = self.BaseLeftShoulder

	local neckOffset = self:GetHumanoidState("N") or CFrame.identity
	local rightShoulderOffset = self:GetHumanoidState("RS") or CFrame.identity
	local leftShoulderOffset = self:GetHumanoidState("LS") or CFrame.identity

	if stance == Stances.Proning then
		local rightFlip = CFrame.Angles(math.rad(0), math.rad(0), math.rad(90))
		local leftFlip = CFrame.Angles(math.rad(0), math.rad(0), math.rad(-90))
		local neckFlip = CFrame.Angles(math.rad(-90), math.rad(0), math.rad(0))

		neckOffset *= neckFlip
		rightShoulderOffset *= rightFlip
		leftShoulderOffset *= leftFlip
	end

	local value = 0

	if itemData and itemData.RightArmMovement then
		value = 1
	end

	rightShoulderOffset = CFrame.identity:Lerp(rightShoulderOffset, value)
	leftShoulderOffset = CFrame.identity:Lerp(leftShoulderOffset, value)

	local neckCFrame:CFrame = baseNeckCFrame * neckOffset
	local rightShoulderCFrame:CFrame = baseRightShoulderCFrame * rightShoulderOffset
	local leftShoulderCFrame:CFrame = baseLeftShoulderCFrame * leftShoulderOffset

	if itemData and item then
		local baseTool6DC0CFrame:CFrame = itemData.GripC0 or CFrame.identity
		local baseTool6DC1CFrame:CFrame = itemData.GripC1 or CFrame.identity

		local tool6D:Motor6D? = self.Character:FindFirstChild("Tool6D", true)

		if tool6D then
			local rX, rY, rZ = (neckOffset):ToOrientation()

			local rotation = CFrame.Angles(-rX, 0, 0) --* CFrame.new(baseNeckCFrame.Position)
			local degreex = math.deg(rX)
			local value = degreex / 90 * -1

			local torso:BasePart = self.Character:FindFirstChild("Torso")
			local rightArm:BasePart = self.Character:FindFirstChild("Right Arm")

			tool6D.C0 = rightShoulderCFrame * baseRightShoulderCFrame:Inverse() --CFrame.Angles(0, math.rad(-90), 0) * CFrame.new(-1, -0.5, 0)
		end
	end

	self.Neck.C0 = neckCFrame
	self.RightShoulder.C0 = rightShoulderCFrame
	self.LeftShoulder.C0 = leftShoulderCFrame
end

Okay so, I want the gun (Tool6D) to be relative to the right arm. What I did was take the rightShoulderOffset (Torso > Right Shoulder > Starting C0 property) and inversed it, and then added it to the rotation CFrame. The rotation CFrame (rightShoulderOffset) is just a rotation CFrame with a rotation on one axis.

This took me a long while to figure out and it seems obvious now but just incase anyone ever decides to do this and runs into the same issue, here you go.