-- Player Vision Detection System -- Detects when other players can see you (no walls blocking) local Players = game:GetService("Players") local RunService = game:GetService("RunService") local LocalPlayer = Players.LocalPlayer -- Configuration local FOV_ANGLE = 90 -- Field of view in degrees (half angle, so total is 180°) local MAX_VISION_DISTANCE = 100 -- Maximum distance they can see local SCAN_INTERVAL = 0.1 -- How often to check (seconds) local VISUALIZE = true -- Show debug visualization -- Convert degrees to radians local FOV_RADIANS = math.rad(FOV_ANGLE) -- Store players who can currently see you local playersWhoSeeYou = {} -- Create GUI for displaying who sees you local function createGUI() local screenGui = Instance.new("ScreenGui") screenGui.Name = "VisionDetectorGUI" screenGui.ResetOnSpawn = false screenGui.Parent = LocalPlayer:WaitForChild("PlayerGui") local frame = Instance.new("Frame") frame.Size = UDim2.new(0, 250, 0, 300) frame.Position = UDim2.new(1, -260, 0, 10) frame.BackgroundColor3 = Color3.fromRGB(30, 30, 30) frame.BackgroundTransparency = 0.3 frame.BorderSizePixel = 0 frame.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 8) corner.Parent = frame local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -20, 0, 30) title.Position = UDim2.new(0, 10, 0, 5) title.BackgroundTransparency = 1 title.Text = "Players Who See You:" title.TextColor3 = Color3.fromRGB(255, 255, 255) title.TextSize = 16 title.Font = Enum.Font.GothamBold title.TextXAlignment = Enum.TextXAlignment.Left title.Parent = frame local listFrame = Instance.new("ScrollingFrame") listFrame.Size = UDim2.new(1, -20, 1, -45) listFrame.Position = UDim2.new(0, 10, 0, 40) listFrame.BackgroundTransparency = 1 listFrame.BorderSizePixel = 0 listFrame.ScrollBarThickness = 6 listFrame.Parent = frame local listLayout = Instance.new("UIListLayout") listLayout.SortOrder = Enum.SortOrder.Name listLayout.Padding = UDim.new(0, 5) listLayout.Parent = listFrame return listFrame end local listFrame = createGUI() -- Update GUI with current players local function updateGUI() -- Clear existing labels for _, child in ipairs(listFrame:GetChildren()) do if child:IsA("TextLabel") then child:Destroy() end end -- Create labels for each player who sees you for playerName, data in pairs(playersWhoSeeYou) do local label = Instance.new("TextLabel") label.Size = UDim2.new(1, 0, 0, 25) label.BackgroundColor3 = Color3.fromRGB(200, 50, 50) label.BackgroundTransparency = 0.5 label.Text = playerName .. " (" .. math.floor(data.distance) .. " studs)" label.TextColor3 = Color3.fromRGB(255, 255, 255) label.TextSize = 14 label.Font = Enum.Font.Gotham label.Parent = listFrame local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 4) corner.Parent = label end end -- Check if a point is within a cone local function isInCone(observerPos, observerLookVector, targetPos, fovRadians, maxDistance) local toTarget = targetPos - observerPos local distance = toTarget.Magnitude -- Check distance first if distance > maxDistance then return false, distance end -- Normalize the vector local directionToTarget = toTarget.Unit -- Calculate the angle between look vector and direction to target local dotProduct = observerLookVector:Dot(directionToTarget) local angleRadians = math.acos(math.clamp(dotProduct, -1, 1)) -- Check if within FOV return angleRadians <= fovRadians, distance end -- Perform raycast to check for walls local function hasLineOfSight(fromPos, toPos, ignoreList) local direction = toPos - fromPos local distance = direction.Magnitude local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = ignoreList raycastParams.FilterType = Enum.RaycastFilterType.Exclude raycastParams.IgnoreWater = true local result = workspace:Raycast(fromPos, direction, raycastParams) -- If no hit, or hit is very close to target position, line of sight is clear if not result then return true end -- Check if we hit something before reaching the target local hitDistance = (result.Position - fromPos).Magnitude return hitDistance >= distance - 2 -- Small tolerance end -- Visualize FOV cone (for debugging) local visualParts = {} local function visualizeCone(character, canSeeLocalPlayer) if not VISUALIZE then return end -- Clear old visualization for this character local charName = character.Name if visualParts[charName] then for _, part in ipairs(visualParts[charName]) do part:Destroy() end end visualParts[charName] = {} local head = character:FindFirstChild("Head") if not head then return end -- Create a cone visualization local cone = Instance.new("Part") cone.Shape = Enum.PartType.Block cone.Size = Vector3.new(0.5, 0.5, MAX_VISION_DISTANCE / 2) cone.CFrame = head.CFrame * CFrame.new(0, 0, -MAX_VISION_DISTANCE / 4) cone.Color = canSeeLocalPlayer and Color3.fromRGB(255, 0, 0) or Color3.fromRGB(100, 100, 255) cone.Transparency = 0.7 cone.CanCollide = false cone.Anchored = true cone.Material = Enum.Material.Neon cone.Parent = workspace table.insert(visualParts[charName], cone) -- Auto-destroy after a short time task.delay(SCAN_INTERVAL + 0.05, function() if cone and cone.Parent then cone:Destroy() end end) end -- Main detection function local function checkVision() local localChar = LocalPlayer.Character if not localChar then return end local localRoot = localChar:FindFirstChild("HumanoidRootPart") local localHead = localChar:FindFirstChild("Head") if not localRoot or not localHead then return end local localPos = localHead.Position -- Clear previous detections playersWhoSeeYou = {} -- Check each other player for _, player in ipairs(Players:GetPlayers()) do if player ~= LocalPlayer then local char = player.Character if char then local humanoid = char:FindFirstChildOfClass("Humanoid") local head = char:FindFirstChild("Head") local root = char:FindFirstChild("HumanoidRootPart") if humanoid and humanoid.Health > 0 and head and root then -- Get the direction the player is facing local lookVector = root.CFrame.LookVector local observerPos = head.Position -- Check if local player is in their FOV cone local inCone, distance = isInCone(observerPos, lookVector, localPos, FOV_RADIANS, MAX_VISION_DISTANCE) if inCone then -- Check line of sight (no walls) local ignoreList = {localChar, char} local hasLOS = hasLineOfSight(observerPos, localPos, ignoreList) if hasLOS then playersWhoSeeYou[player.Name] = { distance = distance, player = player } visualizeCone(char, true) else visualizeCone(char, false) end else visualizeCone(char, false) end end end end end updateGUI() end -- Run the detection loop local lastScan = 0 RunService.Heartbeat:Connect(function() local now = tick() if now - lastScan >= SCAN_INTERVAL then lastScan = now checkVision() end end) -- Clean up visualizations when players leave Players.PlayerRemoving:Connect(function(player) if visualParts[player.Name] then for _, part in ipairs(visualParts[player.Name]) do part:Destroy() end visualParts[player.Name] = nil end end) print("Vision Detection System Activated!") print("Players who can see you will appear in the top-right GUI") print("Red cones = Can see you | Blue cones = Cannot see you")