How would I detect if a part can be seen?

How would I detect if a part is not only on the screen, but also isn’t just covered by a wall? Help would be greatly appreciated. (I’m basically aiming for an effect like Eyes from doors. If you look at it, you get damaged, but if it’s behind a wall, you don’t get damaged)

I don’t think a raycast would work, because a single disturbance would ruin the whole thing. A bit like how a lamppost would make the part undetectable.

1 Like

You could use Raycasting to check if a part is inbetween the player and the part that makes the damage.
Could look something like this (demo code):

local PlayerChar = game.Players.LocalPlayer.Character
local PlayerHumPart =  PlayerChar.HumanoidRootPart
local Target = game.Workspace.Target

local Direction = Target.Position - PlayerHumPart.Position

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {PlayerChar, Target}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

local RaycastResult = workspace:Raycast(PlayerHumPart.Position, Direction, raycastParams )

if (RaycastResult) then
    -- a part/ terrain has been hit
end

If the player looks directly towards the Target with no obstructions you can use the same method. This time you just use the LookVector of the Player and multiply it by some distance. If the ray hits the Target then the player directly looks at them. (Maybe use multiple rays and spread them out as over long distances even the smallest change to the LookVector can have a huge impact of the path that the ray takes)

This is not really possible right now, the best chance you have is Raycasting like @LuauThread said. But, you would need to raycast to every point of the part to see if any point is visible. You could instead raycast from each corner, and the center which would work for most things.

Something like this could work:

local player = game.Players.LocalPlayer

local origins = { -- Center, All corners, all surfaces
	Vector3.new(),

	Vector3.new(1,1,1),
	Vector3.new(1,1,-1),
	Vector3.new(-1,1,-1),
	Vector3.new(-1,1,1),
	Vector3.new(1,-1,1),
	Vector3.new(1,-1,-1),
	Vector3.new(-1,-1,-1),
	Vector3.new(-1,-1,1),

	Vector3.new(1,0,0),
	Vector3.new(-1,0,0),
	Vector3.new(0,1,0),
	Vector3.new(0,-1,0),
	Vector3.new(0,0,1),
	Vector3.new(0,0,-1),
}

local function IsVisible(part, viewer)
	local s = part.Size/2
	local cf = part.CFrame

	local settings = RaycastParams.new()
	settings.FilterDescendantsInstances = {part, player.Character}
	settings.FilterType = Enum.RaycastFilterType.Blacklist

	for _, origin in pairs(origins) do
		local spot = (origin * s) + viewer.Position
		local direction = spot - viewer.CFrame.Position
		local result = workspace:Raycast(viewer.CFrame.Position, direction, settings)
		if result then return result end
	end
end
1 Like

I have tried this, but it doesn’t seem to work.

Answer

You can use a raycast on the camera

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {PlayerChar, Target}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

local RaycastResult = game.Workspace:Raycast(Player.Camera.Focus.p, Camera.CFrame.lookVector * 10, raycastParams)

if (RaycastResult) then
– a part/ terrain has been hit
end

You may want to play around with the *10 to get the distance you want.

i understand this was 2 years ago but can’t you do a simple workaround by making a proximity prompt that has a high range and toggle the property “Requires line of sight” to true and check if that proximity prompt has been shown and if so then that would tell you that the player was able to see that part/attachment the proximity prompt is parented to, you can also make the proximity prompt invisible by setting its style to ‘custom’,

and you can build on this by making a main script that gets all these proximityprompts that are tagged with (for example) “VisibiltyCheck” and have the functions that fire when the proximity prompt is shown and hidden and set a boolean attribute for the part accordingly.