How to make a player holding a tool point it to the cursor?

I am trying to make a tool which on the client is being pointed to wherever the player is pointing. I already managed to get the vertical axis done with the help of this post, but i cant figure out how to make it work for the horizontal axis as well.


I am terrible with CFrames, so I don’t really know what to do here.
This is my current code:

local Camera = workspace.CurrentCamera
local Player = game.Players.LocalPlayer

local char = Player.Character
local origRightS = char:WaitForChild("RightUpperArm"):WaitForChild('RightShoulder').C0
local origNeck = char:WaitForChild("Head"):WaitForChild("Neck").C0

local m = Player:GetMouse()
local IsEquipped = false


script.Parent.Equipped:Connect(function()
	origRightS = char:WaitForChild("RightUpperArm"):WaitForChild('RightShoulder').C0
	origNeck = char:WaitForChild("Head"):WaitForChild("Neck").C0

	renderconnec = game:GetService("RunService").RenderStepped:Connect(function()
		if char:FindFirstChild("RightUpperArm") then
			char.RightUpperArm.RightShoulder.C0 = char.RightUpperArm.RightShoulder.C0:Lerp(CFrame.new(char.RightUpperArm.RightShoulder.C0.Position) * CFrame.Angles(-math.asin((m.Origin.p - m.Hit.p).unit.y), 0, 0) , 0.1)
		end
		if char.Head:FindFirstChild("Neck") then
			char.Head.Neck.C0 = char.Head.Neck.C0:Lerp(CFrame.new(char.Head.Neck.C0.Position) * CFrame.Angles(-math.asin((m.Origin.p - m.Hit.p).unit.y), 0, 0), 0.2)
		end
	end)
end)

script.Parent.Unequipped:Connect(function()
	if renderconnec then
		renderconnec:Disconnect()
	end

	if char:FindFirstChild("RightUpperArm") then
		char.RightUpperArm.RightShoulder.C0 = origRightS
	end
	if char:FindFirstChild("LeftUpperArm") then
		char.LeftUpperArm.LeftShoulder.C0 = origLeftS
	end
	if char.Head:FindFirstChild("Neck") then
		char.Head.Neck.C0 = origNeck
	end
end)

Edit: sorry for the music, didnt know i was also recording audio

1 Like

Here. I also changed the speed of the lerp so that it’s consistent with any framerate. You can play around with the number a little. Basically what I did was just use your code for the y axis, and do the same thing for the x axis, but instead of getting the mouse.hit.y i did mouse.hit.x and then I removed the - at the start. idek tbh but it works lol. oh yeah i did it for the head too. if you dont want that js remove the “x” in the head part of the code and replace it with a 0

local Camera = workspace.CurrentCamera
local Player = game.Players.LocalPlayer

local char = Player.Character
local origRightS = char:WaitForChild("RightUpperArm"):WaitForChild('RightShoulder').C0
local origNeck = char:WaitForChild("Head"):WaitForChild("Neck").C0

local m = Player:GetMouse()
local IsEquipped = false
local moveSpeed = 1 -- 1 is default, increase or decrease by a few decimals
	
script.Parent.Equipped:Connect(function()
	origRightS = char:WaitForChild("RightUpperArm"):WaitForChild('RightShoulder').C0
	origNeck = char:WaitForChild("Head"):WaitForChild("Neck").C0

	renderconnec = game:GetService("RunService").RenderStepped:Connect(function(deltaTime)
		local lerpSpeed = (60*1) / (1/deltaTime)
		
		local mHit = char.PrimaryPart.CFrame:ToObjectSpace(m.Hit)
		local x = math.asin((m.Origin.p - mHit.p).unit.x)

		if char:FindFirstChild("RightUpperArm") then
			char.RightUpperArm.RightShoulder.C0 = char.RightUpperArm.RightShoulder.C0:Lerp(CFrame.new(char.RightUpperArm.RightShoulder.C0.Position) * CFrame.Angles(-math.asin((m.Origin.p - mHit.p).unit.y), x, 0) , lerpSpeed)
		end
		if char.Head:FindFirstChild("Neck") then
			char.Head.Neck.C0 = char.Head.Neck.C0:Lerp(CFrame.new(char.Head.Neck.C0.Position) * CFrame.Angles(-math.asin((m.Origin.p - mHit.p).unit.y), x, 0), lerpSpeed)
		end
	end)
end)

script.Parent.Unequipped:Connect(function()
	if renderconnec then
		renderconnec:Disconnect()
	end

	if char:FindFirstChild("RightUpperArm") then
		char.RightUpperArm.RightShoulder.C0 = origRightS
	end
	if char:FindFirstChild("LeftUpperArm") then
		char.LeftUpperArm.LeftShoulder.C0 = origLeftS
	end
	if char.Head:FindFirstChild("Neck") then
		char.Head.Neck.C0 = origNeck
	end
end)
2 Likes

Thanks so much! I was fiddling around with the values and changing x with y and stuff but for some reason only could get it to work when the player was facing a certain direction.

Edit: it did work finnicky for objects close by, so i changed mHit to the following:

local mHit = char.PrimaryPart.CFrame:ToObjectSpace(m.Hit) * CFrame.new(0,0,-1000)

I tried some more testing, but unfortunately got this weird issue when pointing at parts and being far away from 0,0,0. When I point into the distance it works fine, but when something is closer it does this. Do you know why?

1 Like

Realism does this (but I think it only points exactly at the mouse when the character is facing towards the mouse):

You could make it do what you want if you have a script that faces the character towards the mouse (or at least within a 45 degree angle). You could do that with body movers (e.g. align orientation).

this only works when the player is in first person or sitting, while i want it to happen when players are in third person as well.

1 Like

I was thinking it might work in shift lock too (or something similar that forces the player to face roughly in the direction of the mouse), but that might not be the look you’re going for.

you can use TargetFilter to filter out parts (only looking at the cursor) to make it consistent by adding

mouse.TargetFilter = workspace

After hours of stress and trying stuff out, I managed to get something working with the help of this post. This is my current code and it does not have any weird issues like mentioned before!

local Player = game.Players.LocalPlayer

local origRightS = nil
local origNeck = nil

local mouse = Player:GetMouse()

local clamps = {
	xmin = math.rad(0),
	xmax = math.rad(180),
	ymin = math.rad(-30),
	ymax = math.rad(30),
	zmin = math.rad(-60),
	zmax = math.rad(60),
}

script.Parent.Equipped:Connect(function()
	local char = Player.Character
	
	if char:FindFirstChild('RightUpperArm') then
		origRightS = char.RightUpperArm:WaitForChild('RightShoulder').C0
	end
	if char:FindFirstChild('Head') then
		origNeck = char.Head:WaitForChild("Neck").C0
	end
	
	renderconnec = game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
		local lerpSpeed = 10/(1/deltaTime)
		local cframe = CFrame.new(char.UpperTorso.Position, mouse.Hit.Position) * CFrame.Angles(math.pi/2, 0, 0)
		
		if char:FindFirstChild('RightUpperArm') then
			local x,y,z = (CFrame.new(char.RightUpperArm.RightShoulder.C0.Position) * char.UpperTorso.CFrame:toObjectSpace(cframe)):ToEulerAnglesXYZ()
			local cf2 = CFrame.new(char.RightUpperArm.RightShoulder.C0.Position) * CFrame.Angles(math.clamp(x,clamps.xmin,clamps.xmax),math.clamp(y,clamps.ymin,clamps.ymax),math.clamp(z,clamps.zmin,clamps.zmax)) 
			char.RightUpperArm.RightShoulder.C0 = char.RightUpperArm.RightShoulder.C0:Lerp(cf2 * CFrame.Angles(math.rad(-90),0,0),lerpSpeed)
		end	
		
		if char:FindFirstChild('Head') then
			local x,y,z = (CFrame.new(char.Head.Neck.C0.Position) * char.UpperTorso.CFrame:toObjectSpace(cframe)):ToEulerAnglesXYZ()
			local cf2 = CFrame.new(char.Head.Neck.C0.Position) * CFrame.Angles(math.clamp(x,clamps.xmin,clamps.xmax),math.clamp(y,clamps.ymin,clamps.ymax),math.clamp(z,clamps.zmin,clamps.zmax)) 
			char.Head.Neck.C0 = char.Head.Neck.C0:Lerp(cf2 * CFrame.Angles(math.rad(-90),0,0),lerpSpeed)
		end
	end)
end)

script.Parent.Unequipped:Connect(function()
	local char = Player.Character
	
	if renderconnec then
		renderconnec:Disconnect()
	end

	if char:FindFirstChild("RightUpperArm") then
		char.RightUpperArm.RightShoulder.C0 = origRightS
	end
	if char:FindFirstChild('Head') then
		char.Head.Neck.C0 = origNeck
	end
end)
1 Like

Heres some choppy code I made long time ago,

armOffset= plr.Character.UpperTorso.CFrame:Inverse() * plr.Character.RightUpperArm.CFrame
armWeld= Instance.new("Weld")
armWeld.Part0 = plr.Character.UpperTorso
armWeld.Part1 =plr.Character.RightUpperArm
armWeld.Parent = char

script.Parent.ArmMovement.OnServerEvent:Connect(function(plr,position)
	local cframe = CFrame.new(plr.Character.UpperTorso.Position, position) * CFrame.Angles(math.pi/2, 0, 0)
	armWeld.C0 = armOffset * plr.Character.UpperTorso.CFrame:toObjectSpace(cframe)
end)


-- Local Client
script.Parent.ArmMovement:FireServer(mouse.Hit.Position)
1 Like