How could I achieve this?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I would like to make a NPC rotate his head to face the player whenever it’s nearby.

  2. What is the issue? Include screenshots / videos if possible!
    I’m unable to figure out how to do this. I have tried a script I previously made however it doesn’t function.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    Using Old Scripts.
    After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

-- 
local ShopCharacter = game.Workspace.ShopGuy

local function GetDistance()
	local Character = game.Players.LocalPlayer.Character
	local magnitude_distance = (Character.PrimaryPart.Position - game.Workspace.ShopGuy.PrimaryPart.Position).Magnitude
	return magnitude_distance
end

while true do
if GetDistance() <= 6 then
			local is_in_front = game.Workspace.ShopGuy.PrimaryPart.CFrame:ToObjectSpace(game.Players.LocalPlayer.Character.PrimaryPart.CFrame).Z < 0
			if is_in_front then
				local unit = (game.Workspace.ShopGuy.PrimaryPart.CFrame.Position - game.Players.LocalPlayer.Character.PrimaryPart.Position).unit
		game.Workspace.ShopGuy.Head.Neck.C0 = game.Workspace.ShopGuy.Head.Neck.C0 * CFrame.new(Vector3.new(0, 0, 0), unit) * CFrame.Angles(0, -math.rad(game.Workspace.ShopGuy.PrimaryPart.Orientation.Y), 0)
			end
	end
	wait()
	

I would like to be local and only activate if they are nearby and within 6 studs.

1 Like

you could shorten this script by using
CFrame.LookAt()
i cant really help with any of your code but you really should search how to use that

You could either use a hitbox that represents its distance, have some raycasts at the character’s eye-level. OR, you could just simply do some mathematics to get the right values for the CFrame angles. In this case, I do just that.

I know you’d like the script to be local. But, if you’re wanting the ShopGuy’s head to be seen by the rest of the players, then you’d want the script to be server-sided.

local RunService = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local ShopGuy = workspace.ShopGuy

local Character = Player.Character or Player.CharacterAdded:Wait()

local IsR15 = ShopGuy.Humanoid.RigType == Enum.HumanoidRigType.R15
local SG_Head = ShopGuy.Head
local SG_HRP = ShopGuy.HumanoidRootPart
local SG_Torso = ShopGuy:WaitForChild("Torso") or ShopGuy:WaitForChild("UpperTorso")

local SG_Neck = SG_Torso.Neck::Motor6D
local SG_Waist = IsR15 and SG_Torso:WaitForChild("Waist")::Motor6D

local HumanoidRootPart = Character.PrimaryPart
local Head = Character:WaitForChild("Head")::BasePart

local SG_OGNeckC0 = SG_Neck.C0
local SG_OGWaistC0 = IsR15 and SG_Waist.C0
local SG_OGHeadCFrame = SG_Head.CFrame

local sightDistance = 6 -- Maximum bertical sight distance.

local LimitFactors = { -- Head limitations, giving it a realistic feel. Anything above 1 will make the movement realistically impossible
	Horizontal = 0.7,
	Vertical = 0.6
}

local lookLerpTime = 0.4
local restLerpTime = 0.15

--while task.wait() do <- actually, instead, use RunService.Heartbeat:Wait()
while true do
	local HeadPos = SG_Head.CFrame.Position
	local HRP_Pos = SG_HRP.CFrame.Position
	
	local TorsoLV = ShopGuy.Torso.CFrame.LookVector
	
	local Distance = (SG_Head.CFrame.Position - Head.CFrame.Position).Magnitude
	local inFrontOf = SG_HRP.CFrame:PointToObjectSpace(Head.CFrame.Position).Z < 0
		and Distance <= sightDistance
	
	if inFrontOf then
		local Difference = SG_Head.CFrame.Position.Y - Head.CFrame.Position.Y

		local calcX = math.atan(Difference/Distance) * LimitFactors.Vertical
		local calcZ = (HRP_Pos - Head.CFrame.Position).Unit:Cross(TorsoLV).Y * LimitFactors.Horizontal
		
		if IsR15 then
			SG_Neck.C0 = SG_Neck.C0:Lerp(SG_OGNeckC0 * CFrame.Angles(-calcX, calcZ, 0), lookLerpTime)
			SG_Waist.C0 = SG_Waist.C0:Lerp(SG_OGWaistC0 * CFrame.Angles(-calcX, calcZ, 0), lookLerpTime)
		else
			SG_Neck.C0 = SG_Neck.C0:Lerp(SG_OGNeckC0 * CFrame.Angles(calcX, 0, calcZ), lookLerpTime)
		end
	else
		if IsR15 then
			SG_Neck.C0 = SG_Neck.C0:Lerp(SG_OGNeckC0, lookLerpTime/2)
			SG_Waist.C0 = SG_Waist.C0:Lerp(SG_OGWaistC0, lookLerpTime/2)
		else
			SG_Neck.C0 = SG_Neck.C0:Lerp(SG_OGNeckC0, lookLerpTime/2)
		end
	end 
	
	RunService.Heartbeat:Wait()
end

I may have had a bit of fun making this…