--!native -- Compiled with roblox-ts v3.0.0 local TS = _G[script] local _services = TS.import(script, TS.getModule(script, "@rbxts", "services")) local Players = _services.Players local Workspace = _services.Workspace --!optimize 2 local DetectingTools = {} do local _container = DetectingTools local abs = math.abs local max = math.max local min = math.min local random = Random.new() --dont change the direction! local corners = table.freeze({ 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) }) --*@returns corners in global space local function GetCorners(part, local_space) local part_corners = table.create(8) --takes the position of the part and applies the corners from the center; local half_size = part.Size * 0.5 for _, corner in corners do local part_corner = corner * half_size local _arg0 = if local_space then part_corner else part.CFrame * part_corner table.insert(part_corners, _arg0) end return part_corners end local function PointsLocalSpace(cframe, world_points) local local_points = table.create(8) for _, point in world_points do local _arg0 = cframe:PointToObjectSpace(point) table.insert(local_points, _arg0) end return local_points end --[[ * * checks if the part insode of the zone part * @param zone * @param part * @param fully_inside * @returns ]] local function IsPartInside(zone, part, fully_inside) if fully_inside == nil then fully_inside = true end local zone_half_size = zone.Size * 0.5 --takes the corners of the part local part_corners = GetCorners(part) --converts points of the part to the local space of the zone; local converted_part_corners = PointsLocalSpace(zone.CFrame, part_corners) local is_fully_inside = true for _, converted_corner in converted_part_corners do local is_in_x = abs(converted_corner.X) <= zone_half_size.X local is_in_y = abs(converted_corner.Y) <= zone_half_size.Y local is_in_z = abs(converted_corner.Z) <= zone_half_size.Z local is_inside = is_in_x and is_in_y and is_in_z if not fully_inside and is_inside then return true end --if fully inside makes other calculation is_fully_inside = is_fully_inside and is_inside end return is_fully_inside end _container.IsPartInside = IsPartInside --[[ * * Gets point under the player character (raycast) * @param player * @param max_depth * @param filter_not_anchored * @returns ]] local function GetPointUnderThePlayer(player, max_depth, filter_not_anchored) if filter_not_anchored == nil then filter_not_anchored = true end if player.Character == nil then return nil end local player_position = player.Character:GetPivot().Position --ignores the players characters local instances_to_ignore = {} for _, player in Players:GetPlayers() do if player.Character == nil then continue end local _character = player.Character table.insert(instances_to_ignore, _character) end --ignores not anchored parts if filter_not_anchored then local parts_around = Workspace:GetPartBoundsInRadius(player_position, max_depth) for _, part in parts_around do if part.Anchored then continue end table.insert(instances_to_ignore, part) end end local raycast_parameters = RaycastParams.new() raycast_parameters.FilterDescendantsInstances = instances_to_ignore local _yAxis = Vector3.yAxis local _arg0 = -1 * max_depth local raycast_result = Workspace:Raycast(player_position, _yAxis * _arg0, raycast_parameters) local _result = raycast_result if _result ~= nil then _result = _result.Position end local _condition = _result if _condition == nil then _condition = player_position end return _condition end _container.GetPointUnderThePlayer = GetPointUnderThePlayer local function SamplePoints(part, amount, local_space) local points = table.create(max(amount, 0)) local half_size = part.Size * 0.5 for i = 0, amount do local point = random:NextUnitVector() * half_size points[i + 1] = if local_space then point else part.CFrame * point end return points end local function PointsToViewPortPosition(camera, points) local view_port_points = table.create(8) for _, point in points do local view_port_point_tuple = { camera:WorldToViewportPoint(point) } table.insert(view_port_points, view_port_point_tuple) end return view_port_points end local function GetVerticesInterval(vertices, axis) local result_x = axis:Dot(vertices[1]) local result_y = result_x for _, vertex in vertices do local projection = axis:Dot(vertex) if projection < result_x then result_x = projection end if projection > result_y then result_y = projection end end return result_x, result_y end local function OverlapOnAxis(vertices_0, vertices_1, axis) local x_1, y_1 = GetVerticesInterval(vertices_0, axis) local x_2, y_2 = GetVerticesInterval(vertices_1, axis) return x_2 <= y_1 and x_1 <= y_2 end --[[ * * checks if the position is insode of the part * @param zone * @param point * @returns ]] local function IsPointInside(zone, point) local offset = zone.CFrame:PointToObjectSpace(point) local half_size = zone.Size * 0.5 local is_in_x = abs(offset.X) <= half_size.X local is_in_y = abs(offset.Y) <= half_size.Y local is_in_z = abs(offset.Z) <= half_size.Z return is_in_x and is_in_y and is_in_z end _container.IsPointInside = IsPointInside local function GetFilteredPointsFromScreenPoints(screen_points) local edges = { { screen_points[1][1], screen_points[3][1] }, { screen_points[1][1], screen_points[2][1] }, { screen_points[2][1], screen_points[4][1] }, { screen_points[3][1], screen_points[4][1] }, { screen_points[1][1], screen_points[5][1] }, { screen_points[2][1], screen_points[6][1] }, { screen_points[3][1], screen_points[7][1] }, { screen_points[4][1], screen_points[8][1] }, { screen_points[5][1], screen_points[7][1] }, { screen_points[5][1], screen_points[6][1] }, { screen_points[6][1], screen_points[8][1] }, { screen_points[7][1], screen_points[8][1] } } local filtered_points = table.create(24) for i = 0, #edges - 1 do local _binding = edges[i + 1] local point_0 = _binding[1] local point_1 = _binding[2] if point_0.Z < 0 and point_1.Z < 0 then continue end local distance = max(point_0.Z, point_1.Z) - min(point_0.Z, point_1.Z) local converted_point_0 = Vector3.new(point_0.X, point_0.Y, 0) local converted_point_1 = Vector3.new(point_1.X, point_1.Y, 0) if point_0.Z < 0 then --0 - point.Z; local distance_to_plane = -point_0.Z local t = distance_to_plane / distance converted_point_0 = converted_point_0:Lerp(converted_point_1, t) end if point_1.Z < 0 then local distance_to_plane = -point_1.Z local t = distance_to_plane / distance converted_point_1 = converted_point_1:Lerp(converted_point_0, t) end local _converted_point_0 = converted_point_0 table.insert(filtered_points, _converted_point_0) local _converted_point_1 = converted_point_1 table.insert(filtered_points, _converted_point_1) end return filtered_points end --*WIP local function IsOnTheScreen(camera, part, fully_inside, samples_amount) if fully_inside == nil then fully_inside = false end if samples_amount == nil then samples_amount = -1 end if not fully_inside then if IsPointInside(part, camera.CFrame.Position) then return true end end local part_corners = GetCorners(part) local sampled_points = SamplePoints(part, samples_amount) local _exp = camera local _array = {} local _length = #_array local _part_cornersLength = #part_corners table.move(part_corners, 1, _part_cornersLength, _length + 1, _array) _length += _part_cornersLength table.move(sampled_points, 1, #sampled_points, _length + 1, _array) local screen_points = PointsToViewPortPosition(_exp, _array) local is_fully_inside = true for _, _binding in screen_points do local _ = _binding[1] local on_the_screen = _binding[2] if not fully_inside and on_the_screen then return true end is_fully_inside = is_fully_inside and on_the_screen end if fully_inside and is_fully_inside then return true end --TODO; -- const view_port_points = [Vector3.zero, new Vector3(camera.ViewportSize.X, 0), new Vector3(0, camera.ViewportSize.Y), new Vector3(camera.ViewportSize.X, camera.ViewportSize.Y)]; -- const filtered_points = GetFilteredPointsFromScreenPoints(screen_points); -- //none on the screen -- if (filtered_points.size() === 0) return false; -- const on_x = OverlapOnAxis(view_port_points, filtered_points, Vector3.yAxis); -- const on_y = OverlapOnAxis(view_port_points, filtered_points, Vector3.xAxis); -- return on_x && on_y; return false end _container.IsOnTheScreen = IsOnTheScreen --[[ * // const corners = [ // new Vector3(1, 1, 1), --0 // new Vector3(-1, 1, 1), --2 // new Vector3(1, 1, 1), --0 // new Vector3(1, 1, -1), --1 // new Vector3(1, 1, -1), --1 // new Vector3(-1, 1, -1), --3 // new Vector3(-1, 1, 1), --2 // new Vector3(-1, 1, -1), --3 // new Vector3(1, 1, 1), --0 // new Vector3(1, -1, 1), --4 // new Vector3(1, 1, -1), --1 // new Vector3(1, -1, -1), --5 // new Vector3(-1, 1, 1), --2 // new Vector3(-1, -1, 1), --6 // new Vector3(-1, 1, -1), --3 // new Vector3(-1, -1, -1), --7 // new Vector3(1, -1, 1), --4 // new Vector3(-1, -1, 1), --6 // new Vector3(1, -1, 1), --4 // new Vector3(1, -1, -1), --5 // new Vector3(1, -1, -1), --5 // new Vector3(-1, -1, -1), --7 // new Vector3(-1, -1, 1), --6 // new Vector3(-1, -1, -1), --7 // ]; ]] end return { DetectingTools = DetectingTools, }