Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

How to tell if someone can see an object?

I'm working on a part that does something when you look at it, I'm not exactly sure what I can do and I don't think lookVector would work, but I don't know much about it, I've been doing some research and I haven't found anything helpful, most of the things I found were too vague, or didn't seem like they would work. Any help would be nice, thanks in advance!

3 answers

✓ Accepted answer

You can get the screen position of a 3D point with the WorldToScreenPoint method of the camera.

local screenPoint, isVisible = camera:WorldToScreenPoint(object.Position)

This however doesn't take the size of the object into account. What you can do is take all the corners of the object and see if any of them are on the screen. Here's an example on how this can be implemented:

local localPlayer = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local part = workspace.Part

local GUI = Instance.new("ScreenGui", localPlayer.PlayerGui)
local function drawFrame(topLeft, bottomRight)
	local size = bottomRight - topLeft
	local frame = Instance.new("Frame")

	
	frame.Position = UDim2.new(0, topLeft.X - size.X/2, 0, topLeft.Y - size.Y/2)
	frame.Size = UDim2.new(0, size.X, 0, size.Y)	
	frame.BackgroundTransparency = 0.2
	frame.BackgroundColor3 = BrickColor.Red().Color	
	
	frame.Parent = GUI
	
	game:GetService("Debris"):AddItem(frame, 1/30)
end

local function isPartVisible(obj)	
	local center = obj.Position
	
--	No need to do any extra calculations if the center point is on the screen
	local centerPoint, centerVisible = camera:WorldToScreenPoint(center)
	if centerVisible then
		return true, centerPoint
	end	
	
	local extents = obj.Size/2	
	
	local extentPoints = {
		[1] = (Vector3.new(center.X + extents.X, center.Y + extents.Y, center.Z + extents.Z)),
		[2] = (Vector3.new(center.X - extents.X, center.Y - extents.Y, center.Z - extents.Z)),
		[3] = (Vector3.new(center.X - extents.X, center.Y + extents.Y, center.Z + extents.Z)),
		[4] = (Vector3.new(center.X + extents.X, center.Y - extents.Y, center.Z + extents.Z)),
		[5] = (Vector3.new(center.X + extents.X, center.Y + extents.Y, center.Z - extents.Z)),
		[6] = (Vector3.new(center.X - extents.X, center.Y - extents.Y, center.Z + extents.Z)),
		[7] = (Vector3.new(center.X + extents.X, center.Y - extents.Y, center.Z - extents.Z)),
		[8] = (Vector3.new(center.X - extents.X, center.Y + extents.Y, center.Z - extents.Z)),
	}	
	
	for n = 1, #extentPoints do
		local point = extentPoints[n]
		local screenPoint, isVisible = camera:WorldToScreenPoint(point)
		drawFrame(screenPoint, screenPoint + Vector3.new(10, 10))
		if isVisible then
			return true, screenPoint
		end
	end
	return false
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(isPartVisible(part))
end)

edit: Of course it is possible that the object is on the screen without any of the 9 points being visible. The final method depends on what kind of requirements you have.

1 comment

0

Thanks! All of the others said the same thing, but you also said how I can tell if you can see an object, but I can't see the center, I would've most likely ran into lots of problems if you didn't add that extra comment. Thanks!

The WorldToScreenPoint method returns information about where on the screen a Vector3 is, but also whether or not it's visible.

This seems to be pretty much exactly what you're looking for, with the caveat that it only returns true if the precise Vector3 is visible. If You've got a large object, you might be able to see the edge of it before its .Position is visible on screen.

If you throw a brick into the workspace called "CanYouSeeMe", then the following should, when you click and hold, take away your health whenever you can see it, and give it back to you when you can't.

script.Parent.Equipped:Connect(function(m)
	held = false
	
	m.Button1Down:Connect(function()
		local player = game:GetService("Players").LocalPlayer
		local cam = workspace.CurrentCamera
		local fov = math.rad(workspace.CurrentCamera.FieldOfView)
		local mouse = player:GetMouse()
		local character = player.Character
		held = true
		
		while held and wait() do
			local locationAndDepth, visible = cam:WorldToScreenPoint(workspace.CanYouSeeMe.Position)
			if visible then
				character.Humanoid:TakeDamage(1)
			else
				character.Humanoid.Health = character.Humanoid.Health + 1
			end
		end
	end)
	
	m.Button1Up:Connect(function()
		held = false
	end)
	
	script.Parent.Unequipped:Connect(function()
		held = false
	end)
end)

This discussion is preserved as it was. New answers, comments, and votes are closed.