Random Map Generation out of plots of different sizes

Hello there! I want to make random map generator that contains plots of different sizes like in SCP-3008. I got only this script that works if all plots are 50x50 studs. But if I add plot with different size,script breaks.

local debris = game:GetService('Debris')
local mapmodule = require(game.ServerStorage.Modules.Map)
local mapfolder = workspace.Map
local wallsFolder = workspace.Walls
local StandartSize = 50
local foodScript = require(game.ReplicatedStorage.Modules.Food)
function Find(tbl,val)
	for _, i in pairs(tbl) do
		if i[1] == val[1] and i[2] == val[2] then
			return true
		end
	end
	return false
end



function isInRegion(c,a,b)
	--a-=Vector3.new(0.1,0.1,0.1)
	--a+=Vector3.new(0.1,0.1,0.1)
	local PosCBetweenB = (c - b).Unit * (c - b).Magnitude

	local PosCBetweenA = (c - a).Unit * (c - a).Magnitude

	local PosBetween = (a - b).Unit * (a - b).Magnitude
	
	if math.abs(PosCBetweenB.Z) < math.abs(PosBetween.Z) and math.abs(PosCBetweenA.Z) < math.abs(PosBetween.Z)
		and math.abs(PosCBetweenB.X) < math.abs(PosBetween.X) and math.abs(PosCBetweenA.X) < math.abs(PosBetween.X)  then
		if a.X == c.X and a.Z ~= c.Z or
			a.X ~= c.X and a.Z == c.Z and
			b.X == c.X and b.Z ~= c.Z or
			b.X ~= c.X and b.Z == c.Z then 
		
			return false
		end
		return true
		
	else
		return false
	end
end

local function GetParentUntil(instance)
	if instance and instance.Parent and instance.Parent:GetAttribute('Pickupable') or instance.Parent:GetAttribute('Model') then
		return instance.Parent
	elseif not instance then
		return false
	elseif instance.Parent == workspace or instance:GetAttribute('Location') then
		return false
	else
		return GetParentUntil(instance.Parent)
	end
end
function smallRound(num)
	local drob = num -  math.floor(num)
	--if math.abs(drob) < 0.09 then
	--	return math.abs( math.floor(num))
	--end
	--return math.floor(num)
	if drob < 0.05 then
		return math.floor(num)
	end
	return math.floor(num)
end
function checkOnCollision(vector1,vector2,list)
	local selfV0 = vector1
	local selfV1 = vector2
	local sizeS = Vector3.new(math.abs(selfV0.X-selfV1.X),math.abs(selfV0.Y-selfV1.Y),math.abs(selfV0.Z-selfV1.Z))
	local bottomLeftCornerSelf = selfV0
	local topLeftCornerSelf = selfV0+Vector3.new(sizeS.X,0,0)
	local bottomRightCornerSelf = selfV0 + Vector3.new(0,0,sizeS.Z)
	local topRightCornerSelf = selfV1
	for _, i in pairs(list) do
		local v0 = i[1]
		local v1 = i[2]
		local size = Vector3.new(math.abs(v0.X-v1.X),0,math.abs(v0.Z-v1.Z))
		local bottomLeftCorner = v0
		local topLeftCorner = v0+Vector3.new(size.X,0,0)
		local bottomRightCorner = v0 + Vector3.new(0,0,size.Z)
		local topRightCorner = v1
		local xmin = math.min(selfV0.X,selfV1.X)
		local xmax = math.max(selfV0.X,selfV1.X)
		local zmin = math.min(selfV0.Z,selfV1.Z)
		local zmax = math.max(selfV0.Z,selfV1.Z)
		local region = Region3.new(v0+Vector3.new(-0.1,10,-0.2),v1+Vector3.new(0.1,10,0.1)) 
		local totalFalse = 0
		local isBetween0 = isInRegion(bottomLeftCornerSelf,v0,v1)
		local isBetween1 = isInRegion(topLeftCornerSelf,v0,v1)
		local isBetween2 = isInRegion(bottomRightCornerSelf,v0,v1)
		local isBetween3 = isInRegion(topRightCornerSelf,v0,v1)
		if isBetween0 or isBetween1 or isBetween2 or isBetween3 or totalFalse >= 4 then
			return true,isBetween0,isBetween1,isBetween2,isBetween3,totalFalse
		else
			--return false
		end
	end
	return false
end
function getLocationPos(list,x,z)
	local possibleLocations = {}
	local pos1
	local pos2
	for _, i in pairs(list) do
		local v0 = i[1]
		local v1 = i[2]
		local size = Vector3.new(math.abs(v1.X-v0.X),0,math.abs(v1.Z-v0.Z))
		local bottomLeftCorner = v0
		local topLeftCorner = v0+Vector3.new(size.X,0,0)
		local bottomRightCorner = v0 + Vector3.new(0,0,size.Z)
		local topRightCorner = v1
		for _, i in pairs(game.ServerStorage.Locations:GetChildren()) do
			local iSize = i:GetExtentsSize()
			pos1 =    bottomLeftCorner+Vector3.new(0,0,iSize.Z)
			pos2 = bottomLeftCorner+Vector3.new(iSize.X,0,iSize.Z*2)
			local isCollides,a0,a1,a2,a3,f = checkOnCollision(pos1,pos2,list)
			if not isCollides then
				
				if pos1.X <= x and pos1.Z <= z and pos2.X <= x and pos2.Z <= z then
					table.insert(possibleLocations,{i.Name,pos1})
					continue
				end
			end
			
			pos1 = bottomLeftCorner+Vector3.new(iSize.X,0,0)
			pos2 = bottomLeftCorner+Vector3.new(iSize.X*2,0,iSize.Z)
			local isCollides,a0,a1,a2,a3,f = checkOnCollision(pos1,pos2,list)
			--print(a0,a1,a2,a3,f)
			if not isCollides then
				if pos1.X <= x and pos1.Z <= z and pos2.X <= x and pos2.Z <= z then
					table.insert(possibleLocations,{i.Name,pos1})
					
					continue
				end
			end
			
		end
		for _, i in pairs(possibleLocations) do
			local locationName,pos = mapmodule.ChooseRandomLocationOfList(possibleLocations)
			if locationName then
				local location = game.ServerStorage.Locations[locationName]:Clone()

				location:SetPrimaryPartCFrame(CFrame.new(pos))
				location.Parent = workspace.Map
				AnalizePlot(location)
				return location,pos1,pos2
			end
		end
	end
	return false
end



function Standart(xsize,zsize)
	workspace.MapLoaded.Value = false
	local occupied = {}
	mapfolder:ClearAllChildren()
	wallsFolder:ClearAllChildren()
	local x = 0
	local MaxXmult = 1
	local xMultiplier
	local zMultiplier
	local plots = {}
	while x < xsize*zsize do
		if #occupied > 0 then
			local location,pos1,pos2 = getLocationPos(occupied,xsize,zsize)
			if pos1 and pos2 then
				table.insert(occupied,{pos1,pos2})
			else
				break
			end
		else
			local location = game.ServerStorage.Locations:GetChildren()[math.random(1,#game.ServerStorage.Locations:GetChildren())]:Clone()
			print('An')
			local size = location:GetExtentsSize()
			--location.Parent = workspace.Map
			--location:SetPrimaryPartCFrame(CFrame.new(Vector3.new(0,0,0)))
			
			table.insert(occupied,{Vector3.new(0,0,0),Vector3.new(0+size.X,0,size.Z)})
		end
			wait()
		x+=1
	end
	local xmapsize = xsize
	local zmapSize = zsize
	local westWall = Instance.new('Part',wallsFolder) ; westWall.Anchored = true ; westWall.Size = Vector3.new(10,500,zsize*StandartSize+100)
	local eastWall = Instance.new('Part',wallsFolder) ; eastWall.Anchored = true ; eastWall.Size = Vector3.new(10,500,zsize*StandartSize+100)
	local southWall = Instance.new('Part',wallsFolder) ; southWall.Anchored = true ; southWall.Size = Vector3.new(xsize*StandartSize+100,500,10)
	local northWall = Instance.new('Part',wallsFolder) ; northWall.Anchored = true ; northWall.Size = Vector3.new(xsize*StandartSize+100,500,10)
	westWall.Position = Vector3.new(xmapsize + 5,0,zmapSize/2) 
	eastWall.Position = Vector3.new(-5,0,zmapSize/2) 
	southWall.Position = Vector3.new(xmapsize/2,0,zmapSize+5)
	northWall.Position = Vector3.new(xmapsize/2,0,-5)
	local roof = Instance.new('Part',wallsFolder) ; roof.Anchored = true ; roof.Size = Vector3.new(xmapsize+10,10,zmapSize+10)
	roof.Position = Vector3.new(xmapsize/2,250+5,zmapSize/2)
	workspace.MapLoaded.Value = true
end

script.Parent.Event:Connect(function(xsize,zsize,roadSize)
	Standart(xsize,zsize)
end)

The problem is I dont know how to properly check on collision with plots.

1 Like

i would suggest making a single part for each plot that is the size of everything in the part and check if that 1 part is colliding with any of the other plot hitboxes therefor if it is then you can stop it