Check regions of irregular areas

I have a plot, and I use a simple Region3 check to make sure player is placing blocks within the region/area that they are allowed to place blocks. However, players can unlock other regions (red) and am wanting to know if there’s an efficient way of checking region for irregular shapes, or if I should just do region checks for each individual square.

return function(island, blockPosition)
	local IslandSpawn = island:FindFirstChild("Spawn")
	if not IslandSpawn then return end
	
	local Top = Vector3.new(0, (31 * 3) + 1.5, 0)
	local Bottom = Vector3.new(0, (19 * 3) - 1.5, 0)
	
	local LeftRight = Vector3.new((12 * 3) + 1.5, 0, 0)
	local UpDown = Vector3.new(0, 0, (12 * 3) + 1.5)
	
	-- Check centre region
	local TopRight = IslandSpawn.Position + LeftRight + UpDown + Top
	local BottomLeft = IslandSpawn.Position - LeftRight - UpDown - Bottom
	
	
	--// Check 'island.LandSlots:GetChildren["Purchased"] and do appropriate Region checks there'
	
	local NewRegion = Region3.new(
		BottomLeft,
		TopRight
	)	
	
	local ObjectSpace = NewRegion.CFrame:PointToObjectSpace(blockPosition)
	
	return (math.abs(ObjectSpace.X) <= NewRegion.Size.X / 2)
		and (math.abs(ObjectSpace.Y) <= NewRegion.Size.Y / 2)
		and (math.abs(ObjectSpace.Z) <= NewRegion.Size.Z / 2)
end

Quick example, if a player had the two blue areas unlocked,


I obviously can’t just do a top left/bottom right check, as the area is L shaped

I prefer to raycast downwards to check presence in an irregular area and in very rare circumstances I’d use pure math to check if a part is within a shape. Essentially it’s like your fallback solution; each square is its own region to check over but the downcast helps determine which of those squares should be region-checked to avoid unnecessarily checking other regions.

You can also take the above idea and turn it around instead to use region first and then a form of check, raycast or math, after. The unlocked areas can serve as a bounding box that you can perform a region check on, then you determine if the position is a valid placement space.

For the bottom picture to make an example, the spaces without blocks are still square in shape. The top corner of your bounding box would be the upper left corner of the empty square and your bottom corner would be the bottom right corner of the green square.

image

Region check around the red square. Any position within the blue square is invalidated.

1 Like

I decided to just roll with checking each slot individually, assuming it isn’t too expensive to do, or doesn’t have a large yield time.

local TOP = Vector3.new(0, (31 * 3) + 1.5, 0)
local BOTTOM = Vector3.new(0, (19 * 3) - 1.5, 0)

local LEFT_RIGHT = Vector3.new((12 * 3) + 1.5, 0, 0)
local UP_DOWN = Vector3.new(0, 0, (12 * 3) + 1.5)

return function(plot, blockPosition)
	local LandSlots = plot:FindFirstChild("LandSlots")
	if not LandSlots then return end
	
	for _, landSlot in pairs(LandSlots:GetChildren()) do
		if not landSlot:GetAttribute("Purchased") then continue end
		
		local Centre = landSlot.Position
		
		-- Check centre region
		local TopRight = Centre + LEFT_RIGHT + UP_DOWN + TOP
		local BottomLeft = Centre - LEFT_RIGHT - UP_DOWN - BOTTOM
		
		--// Reference corners \\--
		local NewPart1 = Instance.new("Part")
		NewPart1.Anchored = true
		NewPart1.BrickColor = BrickColor.new("Really red")
		NewPart1.Material = Enum.Material.SmoothPlastic
		NewPart1.Name = "TopRight"
		NewPart1.Size = Vector3.new(1, 1, 1)
		NewPart1.Position = TopRight
		NewPart1.Parent = workspace
		
		local NewPart2 = Instance.new("Part")
		NewPart2.Anchored = true
		NewPart2.BrickColor = BrickColor.new("Really red")
		NewPart2.Material = Enum.Material.SmoothPlastic
		NewPart2.Name = "BottomLeft"
		NewPart2.Size = Vector3.new(1, 1, 1)
		NewPart2.Position = BottomLeft
		NewPart2.Parent = workspace
		
		local NewRegion = Region3.new(
			BottomLeft,
			TopRight
		)
	end
end

My question is how can I effictively incorporate these

local ObjectSpace = NewRegion.CFrame:PointToObjectSpace(blockPosition)

return (math.abs(ObjectSpace.X) <= NewRegion.Size.X / 2)
	and (math.abs(ObjectSpace.Y) <= NewRegion.Size.Y / 2)
	and (math.abs(ObjectSpace.Z) <= NewRegion.Size.Z / 2)

Because, I was using this not just for the placing check, but doing this on mouse move, to show where the block would be, and so this is being called on RenderStepped :grimacing: