How do I make this tool point towards the mouse correctly?

  1. What do you want to achieve? Keep it simple and clear!

I want the arm to be able to point towards the mouse, and you are only limited to pointing it forwards, the left and right to some extent, but not to the back of you.

  1. What is the issue? Include screenshots / videos if possible!

The player’s right arm is not doing what I want it to do. I believe it might be because it was rotated because of the weld that was created or something.

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

I tried changing things in my script but it did not seem to work. I had used code I found on the DevForum and I though I do understand what some things in the code do, I don’t understand it fully because I am pretty much a beginner at Lua.

Here is my code:

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

local X_MIN_DEG = 15
local X_MAX_DEG = 145

local Z_MIN_DEG = -30	
local Z_MAX_DEG = 30

local plr = Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()

local tool = script.Parent

local radLimits = {
	math.rad(X_MIN_DEG),
	math.rad(X_MAX_DEG),

	math.rad(Z_MIN_DEG),
	math.rad(Z_MAX_DEG)
}

local function rotateArm()
	local hrp = char:WaitForChild("HumanoidRootPart")
	local rShoulder = char:WaitForChild("Torso"):WaitForChild("Right Shoulder")

	local mouseHit = mouse.Hit
	local mouseHitPos = mouseHit.Position
	
	local jointDefaultCfWorldSpace = rShoulder.Part0.CFrame*rShoulder.C0
	local jointTargetCfWorldSpace = CFrame.new(jointDefaultCfWorldSpace.Position, mouseHitPos)*CFrame.Angles(math.pi/2, 0, 0)

	-- transform angles
	local dir = (mouseHitPos-jointDefaultCfWorldSpace.Position).Unit
	local x = math.abs(dir.Y*math.pi/2+math.pi/2)
	local z = math.atan2(dir.Z, dir.X)-math.atan2(jointDefaultCfWorldSpace.LookVector.Z, jointDefaultCfWorldSpace.LookVector.X)
	
	x = math.clamp(x, radLimits[1], radLimits[2])
	z = math.clamp(z, radLimits[3], radLimits[4])

	rShoulder.Transform = CFrame.Angles(x, 0, z)
end

local steppedConn
tool.Equipped:Connect(function()
	steppedConn = RunService.Stepped:Connect(function()
		rotateArm(char)
	end)
end)
tool.Unequipped:Connect(function()
	steppedConn:Disconnect()
end)
1 Like

I think the math will be easier if you just move the mouse into joint space instead of moving every else into world space.

I didn’t test this, but it should give the general idea:

local function rotateArm()
	local hrp = char:WaitForChild("HumanoidRootPart")
	local rShoulder = char:WaitForChild("Torso"):WaitForChild("Right Shoulder")

	local jointDefaultCfWorldSpace  = rShoulder.C0:ToWorldSpace(rShoulder.Part0.CFrame)
	local mouseRelativeToShoulder = mouse.Hit:ToObjectSpace(jointDefaultCfWorldSpace)

	local dir = mouseRelativeToShoulder.Position - rShoulder.C0.Position

	-- now that everything's in object space you can imagine that the joint
	-- is sitting at 0,0,0 facing the -Z axis

	-- yaw or pitch of 0 means "straight in front"
	local yaw = math.atan2(-dir.Z, dir.X) -- left/right rotation
	local pitch = math.atan2(dir.Y, -dir.Z) -- up/down rotation

	-- todo: figure out clamping

	-- note: CFrame.Angles applies rotations in Z, Y, X order.
	--       CFrame.fromOrientation applies in Y, X, Z order.
	rShoulder.Transform = CFrame.fromOrientation(yaw, 0, pitch + math.pi/2)
end

You might also want to experiment with CFrame:ToOrientation. Might give you a shortcut.

1 Like

Tried this out, this was the result:

It’s still letting you point to the back of yourself. I’m sure this works by tweaking the code a bit.
Also, I don’t really know how to use CFrame all that well, though I get what it does.

Okay, let me mess around with it a bit, I’m not very familiar with how Motor6Ds work :slight_smile:

1 Like

Had to futz with the axes a lil to get it to work but:

image

There’s probably a better way to go about this, also, but oh well

local YAW_MIN = math.rad(-70) -- left/right (up to +/-180)
local YAW_MAX = math.rad(70)
local PITCH_MIN = math.rad(-30) -- up/down (up to +/-90)
local PITCH_MAX = math.rad(30)

local function rotateArm()
	local hrp = char:WaitForChild("HumanoidRootPart")
	local rShoulder = char:WaitForChild("Torso"):WaitForChild("Right Shoulder")
	
	-- jointWorld is the position of C0 with the rotation of C0*C1:
	local jointWorld = rShoulder.Part0.CFrame * rShoulder.C0
	
	-- joint->mouse vector in "joint space"
	local dirLocal = jointWorld:PointToObjectSpace(mouse.Hit.Position)

	-- yaw or pitch of 0 means "straight in front"
	local yaw = math.atan2(-dirLocal.Z, dirLocal.X) -- left/right rotation
	local pitch = math.asin(dirLocal.Unit.Y) -- up/down rotation (use above to make a triangle with the Y axis)

	local yawClamped = math.clamp(yaw, YAW_MIN, YAW_MAX)
	local pitchClamped = math.clamp(pitch, PITCH_MIN, PITCH_MAX)
	
	-- note: CFrame.Angles applies rotations in Z, Y, X order
	--       CFrame.fromOrientation applies in Y, X, Z order
	rShoulder.Transform = CFrame.fromOrientation(0, yawClamped, pitchClamped + math.pi/2)
end
7 Likes

Thank you! It works. I appreciate how you made it easy change the yaw and pitch. :grin:

Sorry to bump this, but is it possible to make this server sided?

Just use RemoteEvents

1 Like