Look at player script rotating wrong

So I have a script that has an NPC head looking at the player when they reach a certain distance. It works nicely, only, if I have the NPC facing one way, the head will look up and down correctly. However, once i rotate it 90 degrees in either a positive or negative direction it breaks. Instead of looking up and down according to the player, the NPC will rotate its head sideways. Example, instead of the eyes following me when i jump, their ear will look up. (Photos for ref).

Issue:
A

Roated:
B

Its taking the world CFrame value instead of the local. I just don’t know how to change it. Im a little dense with scripts from time to time.

Script:

local Neck = script.Parent.Neck
local NPC = script.Parent.Parent

function getClosestPlayer ()
	local ClosestPlr, ClosestDist = nil, 20
	for i, player in pairs(workspace:GetChildren()) do
		if player:FindFirstChild("Humanoid") and player ~= NPC then
			local distance = (NPC.PrimaryPart.Position - player.PrimaryPart.Position).Magnitude
			if distance < ClosestDist then
				ClosestPlr = player
				ClosestDist = distance
			end
		end
	end
	return ClosestPlr
end
local cframe0 = Neck.C0
while true do
	local player = getClosestPlayer()
	if player then
		local isInFront = NPC.PrimaryPart.CFrame:ToObjectSpace(player.PrimaryPart.CFrame).Z < 0
		if isInFront then
			local unit = - (NPC.PrimaryPart.CFrame.Position - player.PrimaryPart.Position).unit 
			Neck.C0 = cframe0 * CFrame.new(Vector3.new(0,0,0), unit) * CFrame.Angles(0,-math.rad(NPC.PrimaryPart.Orientation.Y),0)
		end
	end
	wait()
end

1 Like

ignore the Y part of the unit thing

local Neck = script.Parent.Neck
local NPC = script.Parent.Parent

function getClosestPlayer ()
	local ClosestPlr, ClosestDist = nil, 20
	for i, player in pairs(workspace:GetChildren()) do
		if player:FindFirstChild("Humanoid") and player ~= NPC then
			local distance = (NPC.PrimaryPart.Position - player.PrimaryPart.Position).Magnitude
			if distance < ClosestDist then
				ClosestPlr = player
				ClosestDist = distance
			end
		end
	end
	return ClosestPlr
end
local cframe0 = Neck.C0
while true do
	local player = getClosestPlayer()
	if player then
		local isInFront = NPC.PrimaryPart.CFrame:ToObjectSpace(player.PrimaryPart.CFrame).Z < 0
		if isInFront then
			local unit = - (NPC.PrimaryPart.CFrame.Position - player.PrimaryPart.Position).unit 
			Neck.C0 = cframe0 * CFrame.new(Vector3.new(0,0,0), unit - Vector3.new(0, unit.Y, 0)) * CFrame.Angles(0,-math.rad(NPC.PrimaryPart.Orientation.Y),0)
		end
	end
	wait()
end
1 Like

Oh sick! Okay, Is there any way to keep the Y rotation whilst keeping its rotation local? to the NPC head or is it impossible due to limitations?

I appreciate the help btw :slight_smile: If the local rotation thing can’t be solved, your revisions will be perfect :smiley:

Basically there are two problems with the unit vector. When the NPC rotates, the perspective of his head changes so the target position must be in that perpective. The perspective is obtained from the HumanoidRootPart of the NPC, who is the one who rotates.
The other problem is that the unit vector must not start at the HumanoidRootPart but at the head for the rotation to be correct.

local unit = -(cframe0.Position - NPC.PrimaryPart.CFrame:PointToObjectSpace(player.PrimaryPart.Position)).unit