I’m trying to make my character aim their head toward the mouse using animation weights instead of manually rotating Motor6Ds. Firing a RemoteEvent 30 times a second per aiming player (to update Motor6D angles) seems taxing on the server. Roblox’s animation system replicates automatically, seems more efficient, and works well in theory. The issue is some visual jank when you go from tilting up to down, and how slow your head takes to tilt once you toggle it.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")
local Up = script:WaitForChild("Up")
local Down = script:WaitForChild("Down")
local TiltUp = humanoid:LoadAnimation(Up)
local TiltDown = humanoid:LoadAnimation(Down)
local lookConnection = nil
local function startLookAt()
lookConnection = RunService.RenderStepped:Connect(function()
local mousePos = mouse.Hit.Position
local rootPos = rootPart.Position
local headPos = head.Position
-- Setting Up Animations for tilting head and limbs
TiltUp:Play()
TiltDown:Play()
TiltUp:AdjustWeight(0)
TiltDown:AdjustWeight(0)
-- Face the Root horizontally toward the mouse (Y rotation)
local horizontalLook = CFrame.new(rootPos, Vector3.new(mousePos.X, rootPos.Y, mousePos.Z))
local _, yaw, _ = horizontalLook:ToEulerAnglesYXZ()
rootPart.CFrame = CFrame.new(rootPos) * CFrame.Angles(0, yaw, 0)
-- Adjust neck pitch (X rotation only)
local direction = (mousePos - headPos).Unit
local pitch = math.asin(direction.Y) -- vertical angle only
local clampedPitch = math.clamp(pitch, math.rad(-50), math.rad(50))
local PitchDeg = math.deg(clampedPitch)
if PitchDeg > 0 then
TiltDown:AdjustWeight(0)
TiltUp:AdjustWeight(PitchDeg/100)
elseif PitchDeg < 0 then
TiltUp:AdjustWeight(0)
TiltDown:AdjustWeight(math.abs(PitchDeg/100))
end
--neck.C0 = originalNeckC0 * CFrame.Angles(-clampedPitch, 0, 0)
end)
end
local function stopLookAt()
if lookConnection then
TiltUp:Stop()
TiltDown:Stop()
lookConnection:Disconnect()
lookConnection = nil
end
--if neck and originalNeckC0 then
--neck.C0 = originalNeckC0 -- Reset neck position
--end
end
local function InputBegan(input,gpe)
if gpe then return end
if input.KeyCode == Enum.KeyCode.F then
if lookConnection then
stopLookAt()
else
startLookAt()
end
end
end
-- Toggle on F key press
UserInputService.InputBegan:Connect(InputBegan)