When the scalar product of two unit vectors is 1, it means that they are pointing in the same direction. Then you can do the scalar product of the position of the player with respect to the part and the lookvector of the part.

But in practice, it is very difficult for two vectors to point in exactly the same direction, so their scalar product will almost never be 1. To solve this we simply consider a value close to 1.

function partIsDirectionOfPlayer(part, player)
local character = player.Character
local head = character and player.Character.Head
if head then
local playerDirection = (head.Position - part.Position).unit
local partDirection = part.CFrame.LookVector.unit
local coef = playerDirection:Dot(partDirection)
return coef > 0.95
end
return false
end

Using some CFrame magic, I was able to create a small system that achieves this for you.

local startPart = workspace.StartPart
local lookPart = workspace.LookPart
local fieldOfView = 180
function isLookPartInFront()
local startPartLookVector = startPart.CFrame.LookVector
local partDifference = (lookPart.CFrame.p - startPart.CFrame.p).Unit
local value = math.pow((startPartLookVector - partDifference).Magnitude/2, 2)
if value >= fieldOfView/360 then
return false
else
return true
end
end
print(isLookPartInFront())

A quick overview of what the variables do and what they’re for:

startPart stores the part that is looking at the other part. In your case, the startPart is the specific part facing in the direction of the player. lookPart is the part being looked at. This would most likely be a child of the character you’re looking at in your example. fieldOfView refers to how strict the viewing angle should be (in degrees). A larger value means a larger angle.

The people who replied above me also have some cool ideas that you should check out. I did not even know about the :Dot method, so I will definitely be looking into it.