I know it has stuff to do with raycasting but I haven’t been able to get it to work.
Basically
2 parts
NPC’s head
Player’s head
controlled by local script
I know it has stuff to do with raycasting but I haven’t been able to get it to work.
Basically
2 parts
NPC’s head
Player’s head
controlled by local script
This code placed in a Local Script will create a loop on hearthbeat that checks if the player is looking at the NPC every frame.
The ray is set on the players Head and will follow the Cameras LookVector as the head don’t move when looking around.
local RunService = game:GetService("RunService")
local Player = game.Players.LocalPlayer
local NPC = game.Workspace -- Refrence the NPC's Character here
local Cam = game.Workspace.CurrentCamera
local IsPlayerLooking = false
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist -- Makes the following array a blacklist.
raycastParams.FilterDescendantsInstances = {Player.Character}
-- We add the players character to the Blacklist so that his character will not interfer the ray.
local DetectionRange = 100 -- The ray will be this long, so the player has to be closer than this to the NPC
-- This check will run on Heartbeat which should be equal to the players FPS.
-- Meaning, IsPlayerLooking will allways be correct.
RunService.Heartbeat:Connect(function()
local raycastResult = workspace:Raycast(Player.Character.Head.CFrame.Position, Cam.CFrame.LookVector * DetectionRange, raycastParams)
if raycastResult then
-- The ray hit something
if raycastResult.Instance:IsDescendantOf(NPC) then
-- The player is looking at the NPC
IsPlayerLooking = true
else
-- The player is looking at something, but its not the NPC
IsPlayerLooking = false
end
else
-- The player is not looking at anything
IsPlayerLooking = false
end
end)
This only triggers when looking directly on a descendant part of the NPC, if you want it to trigger when looking close to the NPC instead, you need a different approach:
local RunService = game:GetService("RunService")
local Player = game.Players.LocalPlayer
local NPC = game.Workspace -- Refrence the NPC's Character here
local Cam = game.Workspace.CurrentCamera
local IsPlayerLooking = false
-- The max distance from the camera hit point to the NPC before he would not be looking.
local MaxDistance = 10
-- This check will run on Heartbeat which should be equal to the players FPS.
-- Meaning, IsPlayerLooking will allways be correct.
RunService.Heartbeat:Connect(function()
-- We get the distance to the NPC.
local DistanceToNPC = (Player.Character.Head.CFrame.Position - NPC.PrimaryPart.CFrame.Position).magnitude
-- We use the distance and the cameras lookvector to make a point which would hit the NPC normally if direct hit took place.
local LookPosition = CFrame.new(Player.Character.Head.CFrame.Position) + Cam.CFrame.LookVector * DistanceToNPC
if (LookPosition.Position - NPC.PrimaryPart.CFrame.Position).magnitude < MaxDistance then
-- The player is looking close or on the NPC.
IsPlayerLooking = true
else
-- Not looking close to the NPC.
IsPlayerLooking = false
end
end)
@MEsAv2 has a fun solution, I’ll offer another one!
vector1:Dot(vector2)
gives you the cosine of the angle between two vectors. You can use this to check the angle between the “player head → npc head” and the “look direction of the player head”:
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local npc = workspace:WaitForChild("Part")
local function CanSee(playerHead, npcHead, maxAngle)
local lookDirection = playerHead.CFrame.LookVector
local towardsNpc = (npcHead.Position - playerHead.Position).Unit
local dotProduct = lookDirection:Dot(towardsNpc)
local cosineAngle = math.cos(maxAngle)
return dotProduct >= cosineAngle
end
-- EXAMPLE
game:GetService("RunService").Stepped:Connect(function()
if CanSee(character.Head, npc, 20) then
npc.BrickColor = BrickColor.Green()
else
npc.BrickColor = BrickColor.Red()
end
end)
Both are successful, so I dont know which one to mark as the Solution, I’ll like both and select the second one as a solution. Thank you!