How would I make an NPC's head look at the closest player's head? (R6)

So basically I’m a new developer, I wanted to make a showcase type game, and make it a bit more lively by adding in R6 NPCs.

I wanted to have these NPCs rotate their own head to look at a Player’s head.

I didn’t really have any clue on how I could achieve this, so after searching up some video tutorials I found a script of such description, it manipulated the NPC’s neck Motor6 joint. The tutorial I tried by SimTek was meant for R15, but i was able to get it to work with R6,

The Script works just fine but it doesn’t have the intended effect I was looking for, the current result being that the NPC’s head is rotating around the neck joint just fine, but bottom of the head is facing the player instead of the obvious front where the face is. I’m not very knowledgeable with this rotation stuff so I came here to see if someone could see which line went wrong?


code here:

local char = script.Parent --this script is inside the Dummy Model
local hrp = char:WaitForChild("HumanoidRootPart")
local torso = char:WaitForChild("Torso") --the neck would have been in the head for R15, but in R6 its here in the torso
local neck = torso:WaitForChild("Neck")

local function FindClosestPlayerHrp(dist)
	local closestHrp = nil
	for i, v in pairs(game.Players:GetChildren()) do
		local tChar = v.Character or v.CharacterAdded:wait()
		local tHead = tChar:FindFirstChild("Head")
		if tHead then
			local tmpDist = (tHead.Position - hrp.Position).Magnitude
			if tmpDist < dist then
				closestHrp = tHead
				dist = tmpDist
			end
		end
	end
	return 	closestHrp, dist
end

while wait() do
	local closestHrp, dist = FindClosestPlayerHrp(100)
	if closestHrp then
		local dir = (closestHrp.Position - hrp.Position).Unit
		local vecA = Vector2.new(dir.X, dir.z)
		local vecB = Vector2.new(hrp.CFrame.LookVector.X, hrp.CFrame.LookVector.X)
		local dotProd = vecA:Dot(vecB)
		local crossProd = vecA:Cross(vecB)
		local angle = math.atan2(crossProd, dotProd)
		
		local ht = closestHrp.Position.Y - hrp.Position.Y
		local upDwnAngle = math.atan(ht/dist)
		
		neck.C0 = CFrame.new(neck.C0.Position) * CFrame.Angles(0, angle, 0) * CFrame.Angles(0, angle, 0)
			* CFrame.Angles(upDwnAngle, 0, 0)
	end
end
1 Like

Heres a suggestion: Put all the players’ characters in a folder in workspace. That’d make it easier and faster than looping through all players and getting the character.

2 Likes

Why do that when you can loop through all player’s without much effort aka its literally what Funkinoe did.

for _, player in pairs(game:GetService("Players"):GetPlayers()) do
   local character = player.Character
   if character then
      -- Code
   end
end
1 Like

Hey I saw your code. Instead of using the above, You can use CFrame.Look at.
So :-

while wait() do
	local closestHrp, dist = FindClosestPlayerHrp(100)
	if closestHrp then
		local LookAt = closestHrp.Position
                local Head = char.Head
                local Start = Head.Position
                local NewCFrame = CFrame.LookAt(Start,LookAt) 
                Head.CFrame = NewCFrame
	end
end

How it works:-
Basically whenever you call CFrame.LookAt() you give it 2 Parameters.
One is the position. It should be at. 2 is the Position to Look at.
It Orients the Object for you so you don’t need to do it.

Fun Fact:
I suck at Orientation Myself :stuck_out_tongue:.

Also you can remove some stuff if you don’t need it above.
I Hope this helps :crossed_fingers:

2 Likes

Sorry for wrong spellings.(if any, it’s not quite fun to write code on mobile :grimacing:

1 Like

Use CFrame.lookAt.

You’re also going to have to Raycast to the nearest player’s head. That way you can check if they’re visible or not.

1 Like

Raycasting is redundant here, You can find the closest and visible player using magnitude and dot products.

1 Like