Making an NPC look at the player while also animating

I’m working on giving an old NPC life by animating them, and I want their head to follow the player. However, the script I’m using seems incompatible with the animations. The animations appear to take priority.
The NPC is an R6 rig.

I’m using this public script for head turning, and it works without animations:

--/// Written by: NyaRemi
--/// Original Head/Waist Script: [https://www.roblox.com/library/1000161193]
--/// Description: Head/Waist movement script for NPC
--/// Updates: 6


------------------ [[ Cofigurations ]] ------------------

-- [ BASIC ] --
local LookAtPlayerRange = 30 -- Distance away that NPC can looks
local LookAtNonPlayer = false -- Looks at other humanoid that isn't player

-- [Head, Torso, HumanoidRootPart], "Torso" and "UpperTorso" works with both R6 and R15.
-- Also make sure to not misspell it.
local PartToLookAt = "Head" -- What should the npc look at. If player doesn't has the specific part it'll looks for RootPart instead.

local LookBackOnNil = true -- Should the npc look at back straight when player is out of range.

local SearchLoc = {workspace} -- Will get player from these locations


-- [ ADVANCED ] --
--[[
	[Horizontal and Vertical limits for head and body tracking.]
	Setting to 0 negates tracking, setting to 1 is normal tracking, and setting to anything higher than 1 goes past real life head/body rotation capabilities.
--]]
local HeadHorFactor = 0.8
local HeadVertFactor = 0.5
local BodyHorFactor = 0.4
local BodyVertFactor = 0.4

-- Don't set this above 1, it will cause glitchy behaviour.
local UpdateSpeed = 0.3 -- How fast the body will rotates.
local UpdateDelay = 0.05 -- How fast the heartbeat will update.

-------------------------------------------------------
wait(1)



--
local Ang = CFrame.Angles
local aTan = math.atan
--
local Players = game:GetService("Players")
--------------------------------------------
local Body = script.Parent

local Head = Body:WaitForChild("Head")
local Hum = Body:WaitForChild("Humanoid")
local Core = Body:WaitForChild("HumanoidRootPart")
local IsR6 = (Hum.RigType.Value==0)
local Trso = (IsR6 and Body:WaitForChild("Torso")) or Body:WaitForChild("UpperTorso")
local Neck = (IsR6 and Trso:WaitForChild("Neck")) or Head:WaitForChild("Neck")	
local Waist = (not IsR6 and Trso:WaitForChild("Waist"))

local NeckOrgnC0 = Neck.C0
local WaistOrgnC0 = (not IsR6 and Waist.C0)

local LookingAtValue = Instance.new("ObjectValue"); LookingAtValue.Parent = Body; LookingAtValue.Name = "LookingAt"
--------------------------------------------


-- Necessery Functions

local ErrorPart = nil
local function GetValidPartToLookAt(Char, bodypart)
	local pHum = Char:FindFirstChild("Humanoid")
	if not Char and pHum then return nil end
	local pIsR6 = (pHum.RigType.Value==0)
	if table.find({"Torso", "UpperTorso"}, bodypart) then
		if pIsR6 then bodypart = "Torso" else bodypart = "UpperTorso" end
	end
	local ValidPart = Char:FindFirstChild(bodypart) or Char:FindFirstChild("HumanoidRootPart")
	if ValidPart then return ValidPart else
		if ErrorPart ~= bodypart then
			--warn(Body.Name.." can't find part to look: "..tostring(bodypart))
			ErrorPart = bodypart
		end
		return nil end
end

local function getClosestPlayer() -- Get the closest player in the range.
	local closest_player, closest_distance = nil, LookAtPlayerRange
	for i = 1, #SearchLoc do
		for _, player in pairs(SearchLoc[i]:GetChildren()) do
			if player:FindFirstChild("Humanoid") and player ~= Body 
				and (Players:GetPlayerFromCharacter(player) or LookAtNonPlayer) 
				and GetValidPartToLookAt(player, PartToLookAt) then
				
				local distance = (Core.Position - player.PrimaryPart.Position).Magnitude
				if distance < closest_distance then
					closest_player = player
					closest_distance = distance
				end
			end
		end
	end
	return closest_player
end

local function rWait(n)
	n = n or 0.05
	local startTime = os.clock()

	while os.clock() - startTime < n do
		game:GetService("RunService").Heartbeat:Wait()
	end
end

local function LookAt(NeckC0, WaistC0)
	if not IsR6 then
		if Neck then Neck.C0 = Neck.C0:lerp(NeckC0, UpdateSpeed/2) end
		if Waist then Waist.C0 = Waist.C0:lerp(WaistC0, UpdateSpeed/2) end
	else
		if Neck then Neck.C0 = Neck.C0:lerp(NeckC0, UpdateSpeed/2) end
	end
end

--------------------------------------------

game:GetService("RunService").Heartbeat:Connect(function()
	rWait(UpdateDelay)
	local TrsoLV = Trso.CFrame.lookVector
	local HdPos = Head.CFrame.p
	local player = getClosestPlayer()
	local LookAtPart
	if Neck or Waist then
		if player then
			local success, err = pcall(function()
				LookAtPart = GetValidPartToLookAt(player, PartToLookAt)
				if LookAtPart then
					local Dist = nil;
					local Diff = nil;
					local is_in_front = Core.CFrame:ToObjectSpace(LookAtPart.CFrame).Z < 0
					if is_in_front then
						if LookingAtValue.Value ~= player then
							LookingAtValue.Value = player
						end
						
						Dist = (Head.CFrame.p-LookAtPart.CFrame.p).magnitude
						Diff = Head.CFrame.Y-LookAtPart.CFrame.Y

						if not IsR6 then
							LookAt(NeckOrgnC0*Ang(-(aTan(Diff/Dist)*HeadVertFactor), (((HdPos-LookAtPart.CFrame.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor, 0), 
								WaistOrgnC0*Ang(-(aTan(Diff/Dist)*BodyVertFactor), (((HdPos-LookAtPart.CFrame.p).Unit):Cross(TrsoLV)).Y*BodyHorFactor, 0))
						else	
							LookAt(NeckOrgnC0*Ang((aTan(Diff/Dist)*HeadVertFactor), 0, (((HdPos-LookAtPart.CFrame.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor))
						end
					elseif LookBackOnNil then
						LookAt(NeckOrgnC0, WaistOrgnC0)
						if LookingAtValue.Value then
							LookingAtValue.Value = nil
						end
					end
				end
			end)
		elseif LookBackOnNil then
			LookAt(NeckOrgnC0, WaistOrgnC0)
			if LookingAtValue.Value then
				LookingAtValue.Value = nil
			end
		end
	end
end)

I’m utilizing Fr0ggity’s Interactive NPCs for animation, in case any of those scripts would cause conflict.

So, how can I get my NPC to look at the player while animating at the same time?

I’ll admit I am an absolute noob at Roblox Animation and CFrame movement, hence why I’m using a public script for this. Please bear with me, I may ask dumb questions. Code examples will help me out big time, if you can provide any.

I’ve temporarily fixed this by just… putting another NPC with working headturning in, making the head/face of my base NPC invisible, and making the body/arms/legs of the other NPC invisible and just… stacking them on top of each other.

Jank, but it works.

Hi! The code you pick seems to me very weird, so i made new, smaller and simpler code:

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local NPCHead = script.Parent:WaitForChild("Head")
local NPCNeck = script.Parent:WaitForChild("Torso"):WaitForChild("Neck")

local DefaultRotation = CFrame.Angles(math.rad(90), math.rad(180), 0)

local LookAtPart

local function FindClosestPlayer()
	for _, v in Players:GetPlayers() do
		local Character = v.Character

		if Character then
			local Head = Character:WaitForChild("Head")

			if not LookAtPart then
				LookAtPart = Head
			else
				if (NPCHead.Position - LookAtPart.Position).Magnitude > (NPCHead.Position - Head.Position).Magnitude then
					LookAtPart = Head
				end
			end

		end
	end
end

RunService.Heartbeat:Connect(function()
	if LookAtPart then
		NPCNeck.C0 = CFrame.new(Vector3.new(0,1,0), LookAtPart.Position-NPCHead.Position) * DefaultRotation
	end
end)

while task.wait(3) do
	FindClosestPlayer()
end

I tested it and it works with animations.
You said that you bad at CFrames, so ask questions if you have them