Circle sensor system

How can I make a system where it makes a bunch of rectangles within a circle and when there’s a block within that circles any of those rectangles that are in the way will stop right when it collides with the ray?

Video example shown from another user who accomplished this:

The white part is an example of
the part it should detect and the blue is all the rectangles forming a circle

Can anybody tell me how I can make this?

Heres the code I that has come closest for now


	local observerPart = workspace.Dot
	local ignoredObjects = {workspace.Viewport}

	local range = 10
	local raysAmount = 360
	local increasement = 10

	local usedParams = RaycastParams.new()
	usedParams.FilterType = Enum.RaycastFilterType.Blacklist
	usedParams.FilterDescendantsInstances = ignoredObjects

	local pi = math.pi

	local function doRaycast(degree) -- Checks if a block is within its range

		-- :: Calculate direction based on angle

		local degreeToRadian = (degree / raysAmount) * pi * 2
		local direction = Vector3.new(math.sin(degreeToRadian), 0, math.cos(degreeToRadian)) * range

		-- :: Return raycast results

		return workspace:Raycast(observerPart.Position, direction, usedParams)

	end

	local function instanceFound(degree, result) -- Changes block to be it's size determined by where the ray got hit

		local origin, direction = observerPart.Position, result.Instance.Position + CFrame.new(Vector3.new(result.Instance.Position.X, observerPart.Position.Y, result.Instance.Position.Z),observerPart.Position)

		local object = workspace.Viewport:FindFirstChild("HitBox"..degree)
		
		if object then
			object.CFrame = CFrame.new((origin + direction)/2, origin) 
			object.Size = Vector3.new(0.0875 * range, 1, (origin - direction).Magnitude)
		else
			object = game.ServerStorage.Dot:Clone()
			object.Parent = workspace.Viewport; object.Name = "HitBox"..degree; object.Anchored = true
			degree = math.rad(degree)
			object.CFrame = CFrame.new((origin + direction)/2, origin) 
			object.Size = Vector3.new(0.0875 * range, 1, (origin - direction).Magnitude)
			object.Color = Color3.fromRGB(57, 245, 255)
		end
		
	end
	
	local function fill(degree) -- Fills up any clear spot
		local origin, direction = observerPart.Position, Vector3.new(observerPart.Position.X + range * math.cos(degree), observerPart.Position.Y, observerPart.Position.Z + range * math.sin(degree)) 
		
		local object = workspace.Viewport:FindFirstChild("HitBox"..degree)
		
		if object then
			object.CFrame = CFrame.new((origin + direction)/2, origin) 
			object.Size = Vector3.new(0.1 * range, 1, (origin - direction).Magnitude)
		else
			object = game.ServerStorage.Dot:Clone()
			object.Parent = workspace.Viewport; object.Name = "HitBox"..degree; object.Anchored = true
			degree = math.rad(degree)
			object.CFrame = CFrame.new((origin + direction)/2, origin) 
			object.Size = Vector3.new(0.0875 * range, 1, (origin - direction).Magnitude)
			object.Color = Color3.fromRGB(57, 245, 255)
		end
	end
	



	while task.wait() do
		for degree = 1, raysAmount, increasement do
			local result = doRaycast(degree)

			if result and result.Instance.Name ~= "HitBox" then
				instanceFound(degree, result)
			else
				fill(degree)
			end
			
			
		end
	end

Basically, it already fills up normally just with fewer parts so it’s not laggy.
Once it detects a part within its radius it changes but this one changes different boxes which aren’t even close to the block.

1 Like

Your best bet would be to contact the person who made the video.

It looks like each rectangular blue Part has a Ray in it that is constantly checking the distance to the white part(s).

Since this is scripting support and you shouldn’t be asking for someone to make a script you should show us the script you are trying to use.

The thing is I have no idea who it is, and I have tried 50 different ways to make this but each one fails in its own different way

Show us the procedures and scripts you used for the most successful way of the 50 different ways you tried. Then others can tell you what needs to be fixed.

This looked like fun so I wrote an implementation. It has a few parts from the place file you’ll need.

RobloxStudioBeta_AIVgKytzwK

CircleScanner.rbxl (39.9 KB)

The sensor can also be inverted via attribute on the Configuration object in the Scanner part.

I added a tad bit of “optimization” which checks if there are any parts around the sensor before it bothers to redraw. This could be improved by checking if those parts move, or their size changes, or the scanner move in subsequent frames.

Another improvement I can envision would be to replace the parts with something like beams or wedges, that will give you a much cleaner shape I think.

Anyway, have fun!

local abs = math.abs;
local tan = math.tan;
local pi = math.pi;
local rad = math.rad;

local scanner = script.Parent;
local beam_example = script.Parent.Beam;
local config = script.Parent.Configuration;

beam_example.Parent = nil;

local raycast_params = RaycastParams.new();
raycast_params.FilterDescendantsInstances = {};

local radius_check_params = OverlapParams.new();
radius_check_params.FilterDescendantsInstances = {scanner};
radius_check_params.FilterType = Enum.RaycastFilterType.Blacklist;

local lines = {};

local function get_line_part(line_number: number)
	if (lines[line_number]) then
		return lines[line_number];
	end
	
	local p = beam_example:Clone();
	p.CanCollide = false;
	p.CanQuery = false;
	p.Parent = scanner;
	
	lines[line_number] = p;
	
	return p;
end

local function draw_cyclinder()
	local cast_cframe = scanner.CFrame;
	local cast_origin = cast_cframe.Position;
	local radius = config:GetAttribute('Radius');
	local sectors = config:GetAttribute('Sectors');
	local inversed = config:GetAttribute('Inverted');
	
	for i = 1, sectors do
		local rotation = i * (360 / sectors);
		
		local line = get_line_part(i);
		local line_size = line.Size;
		
		local angle = CFrame.Angles(0, rad(rotation), 0);
		local offset = CFrame.new(0, 0, radius);
		
		local origin = inversed and cast_cframe * angle * offset or cast_cframe;
		local goal = inversed and cast_origin - origin.Position or (angle * offset).Position;
		
		local ray_result = workspace:Raycast(origin.Position, goal, raycast_params);
		
		local distance = ray_result and ray_result.Distance or radius;
		
		distance = inversed and (ray_result and ray_result.Distance or 0) or distance;
		
		offset = CFrame.new(0, 0, distance / 2);
		
		line.Transparency = distance == 0 and 1 or 0;
		line.CFrame = inversed and origin * CFrame.new(0, 0, -distance / 2) or cast_cframe * angle * offset;
		line.Size = Vector3.new((tan((2 * pi / sectors) / 2) * radius) * 2 , line_size.Y, distance == 0 and 1 or distance);
	end
end

-- Draw initial cylinder.
draw_cyclinder();

while task.wait() do
	local radius = config:GetAttribute('Radius');
	local scanner_position = scanner.Position;
	
	local nearby_parts = workspace:GetPartBoundsInRadius(scanner_position, radius, radius_check_params);
	
	-- Check that there are actually nearby parts that might require a new collision test for the scanner.
	if (#nearby_parts > 0) then
		for i = 1, #nearby_parts do
			local part = nearby_parts[i];
			if (part and abs(part.Position.Y - scanner_position.Y) > part.Size.Y) then
				table.remove(nearby_parts, i);
				i -= 1;
				continue;
			end
		end
		
		raycast_params.FilterType = Enum.RaycastFilterType.Whitelist;
		raycast_params.FilterDescendantsInstances = nearby_parts;

		draw_cyclinder();
	end
end
4 Likes

Thank you so much,


I didn’t really need the code, just an overview of methods I would need to use to create this. It works exactly like I intend the bars to work! :smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.