Help with arm aiming at position

So I am trying to make player’s arm to point at mouse position, but my script doesn’t really work.
Video with the issue:
robloxapp-20220812-1158370.wmv (1.2 MB)
For some reason it moves with whole player and even the player is not really looking at mouse’s position and I have no idea why. If anyone can explain why is it happeing and/or suggest way to fix it would be great.
Script I am surrently using for my hand:

repeat wait(0.5) until game:IsLoaded()
local player = game.Players.LocalPlayer
local char = player.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local RightShoulder = char:WaitForChild("RightUpperArm")
local wpEquipped = false

script.Parent.Equipped:Connect(function()
	wpEquipped = true
end)

script.Parent.Unequipped:Connect(function()
	wpEquipped = false
end)

local function lookDirection()
	if wpEquipped == true then
		RightShoulder.CFrame = CFrame.lookAt(RightShoulder.Position, player:GetMouse().Hit.Position)
	end
end

game["Run Service"].Heartbeat:Connect(lookDirection)

You can’t just use CFrame in this way to change the position or rotation of the arm. This is because the arm is attached via a joint, and attempting to modify CFrame directly will almost always cause problems like this, and therefore you should directly modify the C0/C1 CFrame of the joint which will require some mathematics like inverse kinematics (IK) to find out what value will rotate and/or move the joint to desired position.

“Inverse kinematics is the use of kinematic equations to determine the motion of a robot to reach a desired position. For example, to perform automated bin picking, a robotic arm used in a manufacturing line needs precise motion from an initial position to a desired position between bins and manufacturing machines.” - What Is Inverse Kinematics? - MATLAB & Simulink

Here are some resources to get you started with IK:

Isn’t there a simpler way to reach my goal? Like don’t get me wrong everything you just sent is amazing and I read it all, but it really seems rather complicated and advanced unlike what I am trying to do. This “inverse kinematics” are for advanced hand movement with multiple parts working together, but I just need the whole arm to rotate around the shoulder axis

How about this? It apparently solves the problem on Y-axis, you could probably modify to work on all 3 axis.

1 Like

Since what you sent is made for R6 models, I have rewritten it to be R15 instead, but it really seems it was not made to support R15 because the character doesnt really look the way I want:
robloxapp-20220812-1333478.wmv (599.1 KB)
I dont really understand the math in this script so maybe I overlooked something important that makes the character look somewhere else. If you care enough, you can read my “changed” script:

repeat wait(0.5) until game:IsLoaded()
local replicated = game:GetService("ReplicatedStorage")
local player = game.Players.LocalPlayer
local char = player.Character or game.Players.LocalPlayer.CharacterAdded:Wait()
local origRightS = char:WaitForChild("RightUpperArm"):WaitForChild("RightShoulder").C0
local origLeftS = char:WaitForChild("LeftUpperArm"):WaitForChild("LeftShoulder").C0
local origNeck = char:WaitForChild("Head"):WaitForChild("Neck").C0
local wpEquipped = false
local m = player:GetMouse()

script.Parent.Equipped:Connect(function()
	wpEquipped = true
end)

script.Parent.Unequipped:Connect(function()
	wpEquipped = false
end)


local function lookDirection()
	if wpEquipped == true then
		if char.RightUpperArm:FindFirstChild("RightShoulder") then
			char.RightUpperArm["RightShoulder"].C0 = char.RightUpperArm["RightShoulder"].C0:Lerp(CFrame.new(1, .65, 0) * CFrame.Angles(-math.asin((m.Origin.p - m.Hit.p).unit.y), 1.55, 0, 0) , 0.1)
		end
		if char.LeftUpperArm:FindFirstChild("LeftShoulder") then
			char.LeftUpperArm["LeftShoulder"].C0 = char.LeftUpperArm["LeftShoulder"].C0:Lerp(CFrame.new(-1, .65, 0) * CFrame.Angles(-math.asin((m.Origin.p - m.Hit.p).unit.y), -1.55, 0, 0) , 0.1)
		end
		if char.Head:FindFirstChild("Neck") then
			char.Head["Neck"].C0 = char.Head["Neck"].C0:Lerp(CFrame.new(0, 1, 0) * CFrame.Angles(-math.asin((m.Origin.p - m.Hit.p).unit.y) + 1.55, 3.15, 0), 0.2)
		end
	else
		if char.RightUpperArm:FindFirstChild("RightShoulder") then
			char.RightUpperArm["RightShoulder"].C0 = char.RightUpperArm["RightShoulder"].C0:lerp(origRightS, 0.1)
		end

		if char.LeftUpperArm:FindFirstChild("LeftShoulder") then
			char.LeftUpperArm["LeftShoulder"].C0 = char.LeftUpperArm["LeftShoulder"].C0:lerp(origLeftS, 0.1)
		end

		if char.Head:FindFirstChild("Neck") then
			char.Head["Neck"].C0 = char.Head["Neck"].C0:lerp(origNeck, 0.1)

		end
	end
end

replicated.RemoteEvent.Look.OnClientEvent:Connect(function(PlrAgain, neckCFrame, RsCFrame, LsCFrame)
	local Neck = PlrAgain.Character.Head:FindFirstChild("Neck", true)
	local Rs = PlrAgain.Character.RightUpperArm:FindFirstChild("RightShoulder", true)
	local Ls = PlrAgain.Character.LeftUpperArm:FindFirstChild("LeftShoulder", true)

	if Neck then
		Neck.C0 = neckCFrame
	end

	if Rs then
		Rs.C0 = RsCFrame
	end

	if Ls then
		Ls.C0 = LsCFrame
	end
end)

game["Run Service"].RenderStepped:Connect(lookDirection)

while wait(0.5) do 
	replicated.RemoteEvent.Look:FireServer(char.Head["Neck"].C0, char.RightUpperArm["RightShoulder"].C0, char.LeftUpperArm["LeftShoulder"].C0)
end

Yeah, I am unsure. But using my IKB resource as mentioned earlier, it does the job without a problem.

local Players = game:GetService("Players")
local Player = Players.LocalPlayer

local R15ALIK = require(script.IKB.R15.AL)

local Character = Player.Character or Player.CharacterAdded:Wait()
local UpperTorso = Character:WaitForChild("UpperTorso")
local Mouse = Player:GetMouse()

local RightArmIK = R15ALIK.new(Character, "Right", "Arm")

Mouse.Move:Connect(function()
	RightArmIK:Solve(Mouse.Hit.Position)
end)

-- Make sure to use RightArmIK:Destroy() once you're done using :Solve() function

Here is an example: IKB-Point-Arm-Towards-Mouse.rbxl (40.5 KB)

2 Likes

It works great, but even when I call “RightArmIK:Destroy()” on tool unequip the right hand still remains in the last position, how do I fix that?

My fault! I forgot to restore the original CFrame of joints when :Destroy() method is called. That was IKB resource issue.

IKB-Point-Arm-Towards-Mouse.rbxl (40.5 KB)

Simply replace the IKB folder with the one here.

This works perfectly! One last thing, is there a way to limit player from pointing his arm to certain angles? Or do I have to manullay check if mouse position is too much behind players torso and manually stop the arm movement?

1 Like

You could limit/clamp the numbers that you are putting into :Solve() function. I am not really sure.

1 Like

Hold on another thing popped up, the arm now returns to its previous position, but when I then select the tool again, its broken again:
robloxapp-20220812-1456514.wmv (966.3 KB)

Create the IK with .new() when equipping the tool.

IKB-Point-Arm-Towards-Mouse.rbxl (41.1 KB)

oh I forgot :skull: Anyways it works now with no problems, I will try to work out those limits for hand rotation, but the most important thing works now thanks to you. I really appriciate your help, you are a great person. Have a great day

1 Like

When i use :Destroy() it makes arms stay in their last position, how can I reset their position?

You can try playing with some of the Motor6D properties:

local obj = put your IKInstance here

obj._UpperJoint.Transform = CFrame.identity
obj._LowerJoint.Transform = CFrame.identity

obj._UpperJoint.C0 = Vector3.zero
obj._LowerJoint.C0 = Vector3.zero