How to make an NPC body look at the player

Hello reader! I am trying to make an NPC body look at the player at all times. Like if you walk around them, the will rotate like you. There are some post that also have this but none seem to work. If you need more info or know how to do this, please let me know!

6 Likes

You can use CFrame to do this basically do:

while wait() do 
script.Parent.HumanoidRootPart.CFrame = CFrame.new(script.Parent.HumanoidRootPart.Position,Player.Character.HumanoidRootPart.Position)
end
3 Likes

Does not seem to be working. Do I need a certain script or does the script need to be in a certain part of the humanoid’s body?

You basically want to get the players look vector and the npcs look vector. From there compare the difference of the npcs look vector to the players look vector. From there apply an angular difference with i think its the cross product? It’s this cool cframe trick, egomoose explained it better than me

This is completely useless to do when you can literally just use CFrame.lookAt. No need to make this overcomplicated. @CoderHusk

Hello reader! I am trying to make an NPC body look at the player at all times. Like if you walk around them, the will rotate like you. There are some post that also have this but none seem to work. If you need more info or know how to do this, please let me know!

Use CFrame.lookAt(eye, target) where eye is the NPC’s primary part (you want to maintain it’s position) and target being the player.

8 Likes

Are you trying to make it locally (per each player) or the NPC to look at the nearest player?

local Player = game.Players.LocalPlayer
local NPC = workspace.Dummy -- Replace with with your NPC location
local HuamnoidRootPart = NPC.PrimaryPart
local Target = Player.Character or Player.CharacterAdded:Wait()
Target = Target:WaitForChild("HumanoidRootPart")

while wait() do
	NPC:SetPrimaryPartCFrame(CFrame.lookAt(HuamnoidRootPart.Position, Target.Position * Vector3.new(1, 0, 1) + HuamnoidRootPart.Position * Vector3.new(0, 1, 0)))
end

Place this code in a local script, inside PlayerGui or StarterCharacterScripts. Make sure your NPC has “HumanoidRootPart” set as PrimaryPart.

13 Likes

Thanks! I’ll see what I can do

I think you can use game:GetService("RunService").RenderStepped instead of while wait() do

3 Likes

Ik this is 11 months ago. Maybe put the Animate script in the NPC, could be localscript or normal script I think. Here is a random video, Making NPC look at player - Roblox Studio NPC Tutorial [READ THE DESCRIPTION OR THE PINNED COMMENT] This video makes the NPC look at you only when you are close. ONLY ON R15 so if you are using R6 you’re gonna have to change the script a bit. Make sure you NPC is named Dummy.

1 Like

it doesn’t work at all, no matter what model it is. what were you trying to imply?

1 Like

Hey sorry for being extremely late. But recently I made a headlook system that was designed to work very efficiently and for both players and npcs.

Here is the module source:

-- HashCollision 04/25/23
local module = {}

local tweenService = game:GetService("TweenService")
local players = game:GetService("Players")

local camera = workspace.CurrentCamera

local neck_tween_info = TweenInfo.new(1.3, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)
local neck_offset = Vector3.new(-0, 0.976, 0.061)
local poll_rate = (1 / 12)

local controller = {}
controller.__index = controller

function controller:LookTowards(direction)
    local angle = CFrame.fromOrientation(math.asin(direction.Y) * 1.1, -math.asin(direction.X) * 1.1, 0) + neck_offset

    if self._tween then
        self._tween:Cancel()
        self._tween:Destroy()
    end

    local tween = tweenService:Create(self._neck, neck_tween_info, {C0 = angle})
    tween:Play()

    self._tween = tween
    self.direction = direction
end

function controller:_IdleLoop()
	local lastDirection = self.direction

	while self.active do
		local direction = self._root.CFrame:ToObjectSpace(camera.CFrame).LookVector
			
		if (direction - lastDirection).Magnitude > 0.05 then
			lastDirection = direction

			self.idle = false
			self:LookTowards(direction)
		else
		    self.idle = true
		end

        task.wait(poll_rate)
    end
end

function module.new(character)
    local newController = setmetatable({}, controller)

    newController._root = character:WaitForChild("HumanoidRootPart")
    newController._neck = character:WaitForChild("Head").Neck
    newController.direction = Vector3.new(0, 0, 0)
    newController.isLocal = players:GetPlayerFromCharacter(character) == players.LocalPlayer
    newController.active = true

    task.defer(function()
        newController:LookTowards(Vector3.zero)

        if newController.isLocal then
            newController:_IdleLoop()
        end
    end)

    return newController
end

function controller:Destroy()
    table.clear(self)
    setmetatable(self, nil)
end

return module

Put this code into a ModuleScript somewhere, probably in ReplicatedStorage.
Using this module, you can create a headlook object and instruct it to look in a certain direction, which means we can write a very short script that instructs npcs to look in the players direction.

A very basic one is as follows, feel free to change it to your needs:

local controllers = require(<module here>)
-- ^ Make sure this points to the module script.

local npcFolder = workspace.NPCs
-- Folder or model or whatever of where all your npcs are.

local playerHead = script.Parent:WaitForChild("Head")
-- This variable assumes this script is under StarterCharacterScripts, you can replace this line and obtain the character your own way.

for _, npc in npcFolder:GetChildren() do
	local controller = controllers.new(npc)
    local head = npc.Head

	-- construct an object for later use
	task.spawn(function()
		while task.wait(0.5) do
            local direction = CFrame.lookAt(head.Position, playerHead.Position).LookVector
            -- basic cframe math to compute a direction for the npc to use.

			controller:LookTowards(direction)
		end
	end)
end
6 Likes

unfortunately, i am having no luck on getting this to work, I’m assuming its made for a specific model instead of any r15 character?

This is made and works for an r15 character. Are you having a specific error? I can help you track it down.

does this only work for r15? I tried doing it on a r6 model and it errored out.

2 Likes