Detect if player sees an object in their field of view (if it isn't obstructed)

I want to detect when a player sees an object in their field of view if it isn’t obstructed by an obstruction.

I have made this script:

local enemy = game.Workspace.testenemy

local char = game.Players.LocalPlayer.Character

local function detect(enemyname)
	
local rayOrigion = char.Head.Position
local rayDirection = char.Head.Orientation

local raycastFilter = RaycastParams.new()
raycastFilter.FilterType = Enum.RaycastFilterType.Exclude
raycastFilter.FilterDescendantsInstances = {char}

local raycastResult = workspace:Raycast(rayOrigion, rayDirection * 1000, raycastFilter)

local raycast = game.Workspace:Raycast(rayOrigion,rayDirection)
print(raycastResult)
if raycastResult then
	if raycastResult.Instance.Parent.Name == enemyname then
		
	return raycastResult.Instance.Parent.Name
else
	return
	end
end
end

	while true do
		task.wait(0.2) --for the sake of playtesting ive made this 0.2 instead of empty
		local isVisible = detect(enemy.Name)
		print(isVisible)
		if isVisible == enemy.Name then
			print("visible")
		else
			print("notvisible")
		end
	end

However this is a script for if a player is looking directly at an object, and it doesn’t even work correctly.

(example: looking directly at enemy does not detect it, however jumping on top of it and looking down works)

I have tried alot of things but none of them ended up being more not broken.

Does “field of view” refer to the character’s head or the camera? If you’re locking first-person these may mean the same thing.

You could use the method Camera:WorldToViewportPoint() do determine whether a point is in the field of view of the camera. If so, then construct a ray from the viewport position towards the target and raycast to check for collisions.

1 Like

hello, i understand this but i am confused on how to construct a ray from the viewport position to the target.

	local camera = workspace.CurrentCamera
	
	local vector, inViewport = camera:WorldToViewportPoint(enemy.Head.Position)
	local onScreen = inViewport and vector.Z > 0
	
	if onScreen then
	
	local viewpointtoray = camera:ViewportPointToRay(vector.X,vector.Y * 500)
	print(viewpointtoray, onScreen)
	
	if viewpointtoray then
		return "yeah"
	end

i’ve done this and it returns yes even if theres a wall

sorry if this is really obvious, i dont know how to work with cameras well :<

Your ray direction is set to the orientation of the head, which won’t work well

To get the direction between 2 vectors you substract the origin from the goal (goal.Position - origin.Position)

In your case;

local rayDirection = enemy.PrimaryPart.Position-char.PrimaryPart.Position

You can also remove the multiplication by 1000

local raycastResult = workspace:Raycast(rayOrigion, rayDirection, raycastFilter)

You should also edit your function to use the enemy refrence instead of it’s name

Here you go. This script uses the corners of the object to check if you can see it, by using raycasts

local function getAllCornersFromOrientationAndSize(orientation, size)
	local corners = {}
	for x = -0.5, 0.5, 1 do
		for y = -0.5, 0.5, 1 do
			for z = -0.5, 0.5, 1 do
				table.insert(corners, orientation.Position + orientation:VectorToWorldSpace(Vector3.new(x * size.X, y * size.Y, z * size.Z)))
			end
		end
	end
	return corners
end

local function getOrientationAndSize(obj)
	local orientation, size
	if obj:IsA("Model") then
		orientation, size = obj:GetBoundingBox()
	else
		orientation, size = obj:GetPivot(), obj.Size
	end
	return orientation, size
end

local camera = workspace.CurrentCamera

function IsObjectObscured(obj)
	local orientation, size = getOrientationAndSize(obj)
	local corners = getAllCornersFromOrientationAndSize(orientation, size)
	local cameraPosition = camera.CFrame.Position

	for _, corner in ipairs(corners) do
		local rayDirection = (corner - cameraPosition).Unit
		local params = RaycastParams.new()

		params.FilterDescendantsInstances = {obj}
		params.FilterType = Enum.RaycastFilterType.Exclude

		local raycastResult = workspace:Raycast(cameraPosition, rayDirection * (corner - cameraPosition).Magnitude, params)
		if not raycastResult then
			return false -- At least one corner is unobscured
		end
	end
	return true -- All corners are obscured
end

local isObscured = IsObjectObscured(workspace.Part)
if isObscured then
	print("Object is fully obscured")
else
	print("Object has at least one visible corner")
end