- **What do you want to achieve?
To fix the script or at least to know the reason why it stopped working.
- What is the issue?
Some time ago the code I used to apply inverse kinematics to the player’s right arm stopped working. But I don’t why exactly.
- What solutions have you tried so far?
At first sight, I thought I had accidentally changed something, but after further reviewing, I noticed that it neither does work even on the oldest version of the code. So I guess that the joint behavior in Roblox changed after some update a while ago. But I ain’t totally sure of it, yet.
I’d appreciate any kind of information, thanks. And here’s the code (LocalScript):
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local Target = mouse.Hit
local pi =math.pi
local halfpi =pi/2
local forwardV3 =Vector3.new(0,0,-1) -- Constant
local UserInputService = game:GetService("UserInputService")
local ExternalLooks_folder = game.ReplicatedStorage:WaitForChild('RemoteEvents').ExternalLooks
--[[
OriginCFrame is the CF of the shoulder joint, this can be gotten using some CFrame:
upperTorso.CFrame * shoulderJoint.C0
Note that the shoulderJoint.C0 would be the INITIAL shoulderJoint C0, before anything has been done
targetPos is the target Position you are trying to point to, this will be a Vector3 in the world space
a is the length of the upper arm, I use 0.515
b is the length of the lower arm + the hand, I use 1.1031
--]]
local function solveArm(originCFrame,targetPosition,a,b)
-- Localize the targetPosition in regards to originCFrame
local localized = originCFrame:pointToObjectSpace(targetPosition)
local localizedUnit = localized.unit
-- Construct a CFrame pointing from the shoulder position to the target position
local axis = forwardV3:Cross(localizedUnit)
local angle = math.acos(-localizedUnit.Z)
local plane = originCFrame*CFrame.fromAxisAngle(axis,angle)
-- Get the length from the origin to our target position
local c = localized.Magnitude
-- If c is between the lengths of a and b then return an offsetted plane so that one of the lengths reaches the goal,
-- but the other length is folded so it looks natural
if c < math.max(a,b)-math.min(a,b) then
return plane * CFrame.new(0,0,math.max(b,a)-math.min(b-a)-c), -halfpi, pi
-- If c > a + b then return flat angles and an offsetted plane which reaches its target
elseif c > a+b then
return plane * CFrame.new(0,0,a+b-c), halfpi, 0
-- Otherwise, use the law of cosines
else
local theta1 = -math.acos((-(b * b) + (a * a) + (c * c)) / (2 * a * c)) -- law of cosines, gets the angle opposite b
local theta2 = math.acos(((b * b) - (a * a) + (c * c)) / (2 * b * c)) -- law of cosines, gets the angle opposite a
return plane, theta1 + halfpi, theta2 - theta1
end
end
task.wait(5) --When to load
-- Demonstration for how this can be called:
local character = player.Character
local upperTorso =character:WaitForChild("UpperTorso")
local rightUpperArm =character:WaitForChild("RightUpperArm")
local rightLowerArm =character:WaitForChild("RightLowerArm")
local rightShoulder =rightUpperArm:WaitForChild("RightShoulder")
local rightElbow =rightLowerArm:WaitForChild("RightElbow")
-- Store the initial rotation of the shoulder and elbow joints
local rightShoulderInit =rightShoulder.C0 -- This can be a preset value, since it will always be the same, it is the offset from the UpperTorso to the RightShoulder joint
local rightElbowInit =rightElbow.C0 -- This can be a preset value, since it will always be the same, it is the offset from the RightUpperArm to the RightElbow joint
local tp0 =CFrame.new((upperTorso.CFrame * CFrame.new(1.25,0,-1)).p)*CFrame.Angles(0,math.pi/2,0)
-- Make everyone see your arm's position
local tweenService = game:GetService("TweenService")
ExternalLooks_folder.LookArm.OnClientEvent:Connect(function(otherPlayer, rightShoulderCFRAME, rightElbowCFRAME, goalRightShoulderC0CFRame)
local RightShoulder = otherPlayer.Character.RightUpperArm:FindFirstChild("RightShoulder")
local RightElbow = otherPlayer.Character.RightLowerArm:FindFirstChild("RightElbow")
if RightShoulder then
tweenService:Create(RightShoulder, TweenInfo.new(.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 0, false, 0), {C0 = rightElbowCFRAME}):Play()
end
end)
-- Once you move your mouse, apply the inverse kinematics to your right arm.
mouse.Move:Connect(function()
local posX, posY, posZ = mouse.Hit.X, mouse.Hit.Y, mouse.Hit.Z
local targetPos = Vector3.new(posX, posY, posZ)
local shoulderCF =upperTorso.CFrame * rightShoulderInit
local plane, shoulderAngle, elbowAngle = solveArm(shoulderCF, targetPos, 0.515, 1.031)
local goalRightShoulderC0CFrame = upperTorso.CFrame:toObjectSpace(plane) * CFrame.Angles(shoulderAngle, 0, 0)
rightShoulder.C0 =goalRightShoulderC0CFrame.Rotation + rightShoulder.C0.Position
rightElbow.C0 =rightElbowInit * CFrame.Angles(elbowAngle, 0, 0)
ExternalLooks_folder.LookArm:FireServer(player, rightShoulder.C0, rightElbow.C0, goalRightShoulderC0CFrame)
end)