Is there any way to make an NPC that moves when not looked at?

Hello!

I’m trying to make an NPC that moves towards the player when not being looked at by using Camera:WorldToScreenPoint() , but I don’t exactly know how to use it to make an NPC follow the player.

Also I am trying to handle this all inside of one script, but if it is two, that’s fine as well.

7 Likes

U could try to make a part in front of player eyes if the monsters touches the part it stops.

4 Likes

You could use raycasting to check if the player is looking at the NPC and than use pathfinding service to make the NPC walk towards the player if they are looking away

2 Likes

That probably would not work due to:

  • I would need to make the part REALLY big.

  • The NPC would not touch the part on the Y axis.

  • Even if it was on the Y axis it would just simply too much to handle that large of a hitbox.

1 Like

I kinda want to stick to using WorldToScreenPoint()

1 Like

IMO it is too expensive to do that because it is a constant looped check for every player (efficiency). I think a smaller hitbox that is like an invisible accessory/welded part would be best with a listener on it. If someone is within that range - stop movement.

1 Like

kuva_2021-12-28_122054
So have this Events and Script in your workspace, and a LocalScript in PlayerGui.
In Script paste:

local npc = workspace.Dummy -- Your NPC
local hum = workspace.Dummy:WaitForChild("Humanoid")
local head = workspace.Dummy:WaitForChild("Head")

while true do
	wait(0.1)
	local canmove = true
	for i,player in ipairs(game.Players:GetChildren()) do
		local islooking = workspace.Events.IsLookingAt:InvokeClient(player,head.Position)
		if islooking == true then
			if player.Character then
				if player.Character.Humanoid.Health > 0 then
					canmove = false
				end
			end
		end
	end
	if canmove == false then
		hum.WalkSpeed = 0
	else
		hum.WalkSpeed = 16 -- Speed of the NPC
	end
end

and in LocalScript (in the PlayerGui) paste:

local plr = game.Players.LocalPlayer

function onevent(position)
	local camera = workspace.CurrentCamera
	local islooking = false
	local _,isoncamera = camera:WorldToScreenPoint(position)
	if isoncamera then
		islooking = true
	else
	end
	return islooking
end

workspace.Events.IsLookingAt.OnClientInvoke = onevent

Now in the script just change npc = workspace.Dummy to the NPC u want

10 Likes

And of course your NPC must have own follow script

1 Like

Thank you so much! It works perfectly!

1 Like

One question though, is there any way I can make it so that the NPC isn’t able to be detected through walls?

Raycasting is the only way to do this I think

with a ray, but i cant help further rn cause im on my school laptop

has anyone found a solution to this? im having a hard time setting up a raycast for this

found out a more efficient way to do this using dot3

How did you do it? I need a raycast version as well :smile:

ill give out the basics here
im doing all of this thru the npc’s movement script so none of this is local (i wont bother with that)

add this to your npc’s follow script

local head = script.Parent.Head
local HRP = script.Parent.HumanoidRootPart
local Hum = script.Parent.Humanoid
local FOV = 60 -- field of view of the player
local range = math.huge -- basically how far a player can look at the npc until they stop
local PlayerService = game:GetService("Players")

local function GetCharacters() -- will make it so other characters wont block out the npc from your fov
	local Characters = {}

	for _, b in PlayerService:GetPlayers() do
		table.insert(Characters, b.Character)
	end
	return Characters
end


local function CheckLineOfSight(Start, End) -- raycasting, basically makes it so the npc isnt detected thru walls
	local Params = RaycastParams.new()
	Params.FilterDescendantsInstances = {script.Parent, GetCharacters()}
	Params.FilterType = Enum.RaycastFilterType.Exclude

	local Raycast = game.Workspace:Raycast(Start, End - Start, Params)

	if Raycast then
		return false
	else
		return true
	end
end

function detectNpc(target)
	local Character = target.Parent

	if Character then
		if Character.Head then
			local NPCToCharacter = (head.Position - Character.Head.Position).Unit
			local NPCLookVector = Character.Head.CFrame.LookVector

			local DotProduct = NPCToCharacter:Dot(NPCLookVector)
			local Angle = math.deg(math.acos(DotProduct))

			local Distance = (Character.HumanoidRootPart.Position - HRP.Position).Magnitude

			if Angle <= FOV and Distance <= range and CheckLineOfSight(Character.Head.Position, head.Position) then
				Hum.WalkSpeed = 0
				-- looked
			else
				Hum.WalkSpeed = 16
				-- not looked
			end
		end
	end
end

after that i just added detectNpc in a while loop to have more faster detection speed, although theres
probably a better way to do that.
i set the target to the player’s HRP

the result should probably be something like this:

2 Likes

Thank you very much for providing this. Could you kindly explain further how you implement this in the follow script because when I try using this in my current follow script, it only makes it follow the player once then once they look at the npc it just stops and never moves again.

image
i put it in the same place where the npc is chasing the player.
where did you place detectNpc in your follow script?

1 Like

Thank you very much for your help. I was able to fix it once I used a different follow script.

1 Like