Trouble figuring out AABB collisions with parts

so i’ve been working a dungeon generation script, and i have the basic room generation completed. i am having an issue with moving the parts so that none of them are colliding. i was recommended AABB collision methods, but i am fairly new to collisions and physics so i have absolutely no idea how to implement them. see code examples and the gif below

my basic cell generation

local function spawnCells()
	local spawned = 0
	for i = 1, gameConfig.cells.amount do
		local cell = Instance.new("Part")
		cell.CanCollide = false
		cell.Anchored = true
		local cellSettings = {
			size = {
				x = math.random(gameConfig.cells.min_sizes.x, gameConfig.cells.max_sizes.x),
				z = math.random(gameConfig.cells.min_sizes.z, gameConfig.cells.max_sizes.z)
			}
		}
		cell.Size = Vector3.new(cellSettings.size.x, 1, cellSettings.size.z)
		local x, z = getRandomPointInCircle(gameConfig.cells.radius)
		cell.Position = Vector3.new(x,1,z)
		cell.TopSurface = Enum.SurfaceType.Smooth
		cell.Name = "cell"..i
		cell.Parent = workspace.dungeon
		
		spawned += 1
		task.wait(.1)
	end
	if spawned == gameConfig.cells.amount then
		print("--| rooms generated successfully | checking collisions")
		return true, spawned
	else
		warn("[error] could only generate " .. spawned .. " rooms | check code")
		return true, spawned
	end
end

any links to articles that may be helpful or some advice would be appreciated, i have been searching for a while now, but they all seem to do with UI

Firstly, there is a difference between collision detection and collision response. For AABB, the concept is generally take your shapes and check if there is overlap when projected on the x axis, then check overlap on the y. The shape is colliding only if both the x and the y (and Z for 3D) overlap tests pass. Of course a collision is only guaranteed in this case because it looks like your shapes are axis aligned boxes.

When you’ve determined your shapes are colliding you need to figure out how you intend to make them not collide. The simplest method is just give them a small force pushing away from what they are colliding with (the center) and just keep doing that until they have all separated. Of course, depending on your specific needs, this step will be different. Like if you want it to favor separating on the x axis, the implantation above won’t be great.

2 Likes

sounds reasonable and i think i know how ill implement it. appreciate your insight

I was looking at this exact problem just now. Wrote some code to check whether 2 parts are

Here’s the important bits

-- Some vector math, for calculating the pos/size of the overlap
local aDir,bDir=(a.Position-b.Position).Unit,(b.Position-a.Position).Unit
	
	local aSign,bSign = Vector3.new(math.sign(aDir.X),math.sign(aDir.Y),math.sign(aDir.Z)),Vector3.new(math.sign(bDir.X),math.sign(bDir.Y),math.sign(bDir.Z))

	local aBound,bBound = a.Position-Vector3.new(a.Size.X/2,0,a.Size.Z/2) * aSign,b.Position-Vector3.new(b.Size.X/2,0,b.Size.Z/2) * bSign
	
	
	
	local xLength,zLength = math.max((aBound.X-bBound.X),(bBound.X-aBound.X)),math.max((aBound.Z-bBound.Z),(bBound.Z-aBound.Z))

-- Get the lowest and highest X & Z values. 

	local xMin,xMax = math.max(aBound.X-a.Size.X/2,bBound.X-b.Size.X/2), math.min(aBound.X-a.Size.X/2,bBound.X-b.Size.X/2)

	local zMin,zMax = math.max(aBound.Z-a.Size.Z/2,bBound.Z-b.Size.Z/2), math.min(aBound.Z-a.Size.Z/2,bBound.Z-b.Size.Z/2)

-- -- Check if the upper bounds of part 1 are not higher than the lower bounds of part 2, etc.
	if aBound.X >= b.Position.X-b.Size.X/2 and aBound.X <= b.Position.X+b.Size.X/2 or aBound.X <= b.Position.X-b.Size.X/2 and aBound.X >= b.Position.X+b.Size.X/2  then
end

if aBound.Z >= b.Position.Z-b.Size.Z/2 and aBound.Z <= b.Position.Z+b.Size.Z/2 or aBound.Z <= b.Position.Z-b.Size.Z/2 and aBound.Z >= b.Position.Z+b.Size.Z/2  then
end
2 Likes

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