Hello! I am currently working on a start menu screen for my new game, and I need help coding the humanoid NPC’s head to track/watch the player’s cursor.
Please note that I want the head to watch the 2D cursor position on your screen/camera. NOT the mouse.hit.p or the object in 3D space in which the mouse is pointing at.
I know it sounds complicated, but somehow I figured out a tolerable method of achieving this. As shown in the example below, I have managed to successfully write a code which will watch the player’s cursor correctly. However it will only work for anchored parts. In other words, I can’t use the head’s CFrame or the NPC will break.
LocalScript inside of StarterPlayerScripts:
local rs = game:GetService("RunService")
local player = game:GetService("Players").LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local object = workspace:WaitForChild("WatchPart") -- BasePart that will watch the cursor. Anchored.
rs.RenderStepped:Connect(function()
local cursorPosition = camera.CFrame.Position + camera:ViewportPointToRay(mouse.X, mouse.Y).Direction * 10
object.CFrame = CFrame.new(object.Position, cursorPosition)
end)
Let me know if you come up with any methods of watching the player’s 2D cursor position through the head of a humanoid NPC. I’ve been stuck on this one for quite some time, and I would really appreciate some help. I can also provide further information if needed.
I used the technique and attempted to convert it to R6, but I’m bad at CFrames so I’m having a little trouble making it come out correctly.
Here is the code I’m using:
local rs = game:GetService("RunService")
local player = game:GetService("Players").LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local rig = workspace.Rig1
rig.Torso.Neck.MaxVelocity = 1/3
local NeckOriginC0 = rig.Torso.Neck.C0
rs.RenderStepped:Connect(function()
local head = rig:FindFirstChild("Head")
local neck = rig:FindFirstChild("Torso"):FindFirstChild("Neck")
local root = rig:FindFirstChild("HumanoidRootPart")
if head and neck and root then
local torso = rig:FindFirstChild("Torso")
local TorsoLookVector = torso.CFrame.LookVector
local HeadPosition = head.CFrame.p
local Point = mouse.Hit.p
local Distance = (head.CFrame.p - Point).Magnitude
local Difference = head.CFrame.Y - Point.Y
neck.C0 = neck.C0:Lerp(NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) / 2), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 0.5, 0), 0.5 / 2)
end
end)
It resulted in the NPC heads turning in unusual directions, as shown in the picture below:
Terribly sorry for this late reply. I actually solved this two days ago but then forgot to respond. Anyways, here’s the code; it works for both R15 and R6. You may need to adjust the Roll value or just set it to zero if you don’t like it.
Code:
local RunService = game:GetService("RunService")
local Player = game:GetService("Players").LocalPlayer
local PlayerMouse = Player:GetMouse()
local Camera = workspace.CurrentCamera
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local IsR6 = (Humanoid.RigType == Enum.HumanoidRigType.R6)
local Head = Character:WaitForChild("Head")
local Torso = if IsR6 then Character:WaitForChild("Torso") else Character:WaitForChild("UpperTorso")
local Neck = if IsR6 then Torso:WaitForChild("Neck") else Head:WaitForChild("Neck")
local Waist = if IsR6 then nil else Torso:WaitForChild("Waist")
local NeckOriginC0 = Neck.C0
local WaistOriginC0 = if Waist then Waist.C0 else nil
Neck.MaxVelocity = 1/3
local AllowedStates = {Enum.HumanoidStateType.Running, Enum.HumanoidStateType.Climbing, Enum.HumanoidStateType.Swimming, Enum.HumanoidStateType.Freefall, Enum.HumanoidStateType.Seated}
local IsAllowedState = (table.find(AllowedStates, Humanoid:GetState()) ~= nil)
local find = table.find
local atan = math.atan
local atan2 = math.atan2
Humanoid.StateChanged:Connect(function(_, new)
IsAllowedState = (find(AllowedStates, new) ~= nil)
end)
local updatesPerSecond = 10
RunService.RenderStepped:Connect(function(deltaTime: number)
if IsAllowedState then
local HeadPosition = Head.Position
if Neck then
local MousePos = PlayerMouse.Hit.Position
local TranslationVector = (HeadPosition - MousePos).Unit
local Pitch = atan(TranslationVector.Y)
local Yaw = TranslationVector:Cross(Torso.CFrame.LookVector).Y
local Roll = atan(Yaw)
local NeckCFrame
if IsR6 then
NeckCFrame = CFrame.Angles(Pitch, Roll, Yaw)
else
NeckCFrame = CFrame.Angles(-Pitch * 0.5, Yaw, -Roll * 0.5)
local waistCFrame = CFrame.Angles(-Pitch * 0.5, Yaw * 0.5, 0)
Waist.C0 = Waist.C0:Lerp(WaistOriginC0 * waistCFrame, updatesPerSecond * deltaTime)
end
Neck.C0 = Neck.C0:Lerp(NeckOriginC0 * NeckCFrame, updatesPerSecond * deltaTime)
end
end
end)
It worked! The code successfully allowed the R6 character to track my cursor. Thank you so much for taking the time to write this code. I really appreciate your help!
Edit:
The usage of Mouse.Hit.Position for my menu screen resulted in the head tracking awkwardly, from a distance in depth away from the player’s camera. So after a little experimenting, I was actually able to implement my original line of code, and replace the Mouse.Hit.Position with camera.CFrame.Position - Vector3.new(0,1,0) + camera:ViewportPointToRay(mouse.X, mouse.Y).Direction * 14 and it worked PERFECTLY. I’m very happy with the results!
For resourceful purposes, here is the simplified version of the code I’m running:
local rs = game:GetService("RunService")
local ps = game:GetService("Players")
local player = ps.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local rig = workspace:WaitForChild("Rig")
local humanoid = rig:FindFirstChildOfClass("Humanoid")
local head = rig:FindFirstChild("Head")
local torso = rig:FindFirstChild("Torso")
if humanoid and head and torso then
local neck = torso:FindFirstChild("Neck")
local NeckOriginC0 = neck.C0
rs.RenderStepped:Connect(function()
local position = camera.CFrame.Position - Vector3.new(0,1,0) + camera:ViewportPointToRay(mouse.X, mouse.Y).Direction*14
local TranslationVector = (head.Position - position).Unit
local Pitch = math.atan(TranslationVector.Y)
local Yaw = TranslationVector:Cross(torso.CFrame.LookVector).Y
local NeckCFrame = CFrame.Angles(Pitch, 0, Yaw)
neck.C0 = neck.C0:Lerp(NeckOriginC0 * NeckCFrame, 0.15)
end)
end
I was wondering if the Npc could also smoothly turn its HumRootPart while looking to the 2D mouse cursor. Is there a method to do this. (Sorry for the late reply)