Untitled
unknown
lua
a year ago
9.0 kB
12
Indexable
local pointsList = {}
task.wait(0.5)
local padding = 0.01 -- Keep padding small to minimize gaps
function generatePart(position)
local part = Instance.new("Part")
part.Size = Vector3.new(.4, .4, .4)
part.Position = position
part.Material = Enum.Material.Neon
part.Color = Color3.fromRGB(255, 0, 0)
part.Anchored = true
part.Parent = game.Workspace.VisualizationPoints
return part
end
table.insert(pointsList, script.Parent.Bounds.Attachment.WorldCFrame.Position)
local function movePartsTopLeftVerticeTo(part, position)
local size = part.Size
local normalSize = Vector3.new(size.X + padding, size.Y + padding, size.Z + padding)
local topLeftOffset = Vector3.new(-normalSize.X / 2, -normalSize.Y / 2, -normalSize.Z / 2)
local currentTopLeftPosition = part.Position + topLeftOffset
local offset = position - currentTopLeftPosition
part.Position = part.Position + offset
end
local function registerVertices(part)
local temp = {}
local size = part.Size
size = Vector3.new(size.X + padding, size.Y + padding, size.Z + padding)
local topLeftOffset = Vector3.new(-size.X / 2, -size.Y / 2, size.Z / 2)
local currentTopLeftPosition = part.CFrame.Position + topLeftOffset
table.insert(temp, currentTopLeftPosition)
local topRightOffset = Vector3.new(-size.X / 2, -size.Y / 2, -size.Z / 2)
local currentTopRightPosition = part.CFrame.Position + topRightOffset
table.insert(temp, currentTopRightPosition)
local bottomLeftOffset = Vector3.new(size.X / 2, -size.Y / 2, size.Z / 2)
local currentBottomLeftPosition = part.CFrame.Position + bottomLeftOffset
table.insert(temp, currentBottomLeftPosition)
local bottomRightOffset = Vector3.new(size.X / 2, -size.Y / 2, -size.Z / 2)
local currentBottomRightPosition = part.CFrame.Position + bottomRightOffset
table.insert(temp, currentBottomRightPosition)
return temp
end
local function isInContainer(part)
local box = script.Parent.Bounds
local size = part.Size
local partSize = Vector3.new(size.X + padding, size.Y + padding, size.Z + padding)
local partCFrame = part.CFrame
local boxCFrame, boxSize = box.CFrame, box.Size
local partMin = partCFrame.Position - (partSize / 2)
local partMax = partCFrame.Position + (partSize / 2)
local boxMin = boxCFrame.Position - (boxSize / 2)
local boxMax = boxCFrame.Position + (boxSize / 2)
return partMin.X >= boxMin.X and partMax.X <= boxMax.X and
partMin.Y >= boxMin.Y and partMax.Y <= boxMax.Y and
partMin.Z >= boxMin.Z and partMax.Z <= boxMax.Z
end
local function isOverlapping(part)
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Include
local children = script.Parent.Pending:GetChildren()
local removeIndex = table.find(children, part)
table.remove(children, removeIndex)
params.FilterDescendantsInstances = children
local cframe = part.CFrame
local partSize = part.Size
partSize = Vector3.new(partSize.X + padding, partSize.Y + padding, partSize.Z + padding)
local parts = workspace:GetPartBoundsInBox(cframe, partSize, params)
return #parts > 0
end
local function returnRelativeMagnitude(position)
local offset = position - script.Parent.Bounds.Attachment.WorldCFrame.Position
return math.abs(offset.X) + (math.abs(offset.Y)) + (500000000 * math.abs(offset.Z))
end
local function tryAllRotationsAndPlace(box, pointsList)
local bestPoint = nil
local bestOrientation = nil
local minMagnitude = math.huge
for _, rotation in ipairs({0, 90, 180, 270}) do
box.Orientation = Vector3.new(0, rotation, 0)
for _, point in ipairs(pointsList) do
movePartsTopLeftVerticeTo(box, point)
if not isOverlapping(box) and isInContainer(box) then
local magnitude = returnRelativeMagnitude(point)
if magnitude < minMagnitude then
minMagnitude = magnitude
bestPoint = point
bestOrientation = rotation
end
end
end
end
return bestPoint, bestOrientation
end
function putPartAbovePart(partAbove, partBelow)
local padding2 = 0.01
local partAboveSize = Vector3.new(partAbove.Size.X + padding2, partAbove.Size.Y + padding2, partAbove.Size.Z + padding2)
partAbove.Position = Vector3.new(partAbove.Position.X, partBelow.Position.Y + partBelow.Size.Y / 2 + partAboveSize.Y / 2, partAbove.Position.Z)
end
local function getVertices(part)
local padding2 = -1
local size = part.Size
size = Vector3.new(size.X + padding2, size.Y + padding2, size.Z + padding2)
local topLeft = part.CFrame * CFrame.new(-size.X / 2, size.Y / 2, -size.Z / 2).Position
local topRight = part.CFrame * CFrame.new(size.X / 2, size.Y / 2, -size.Z / 2).Position
local bottomLeft = part.CFrame * CFrame.new(-size.X / 2, size.Y / 2, size.Z / 2).Position
local bottomRight = part.CFrame * CFrame.new(size.X / 2, size.Y / 2, size.Z / 2).Position
return {topLeft, topRight, bottomLeft, bottomRight}
end
local function compFunc(part, partAbove)
return (part.Position - partAbove.Position).Magnitude
end
local function getTopLeftAndBottomRightVertices(partAbove)
local size = partAbove.Size
size = Vector3.new(size.X + padding, size.Y + padding, size.Z + padding)
local topLeftOffset = Vector3.new(-size.X / 2, -size.Y / 2, size.Z / 2)
local currentTopLeftPosition = partAbove.CFrame.Position + topLeftOffset
local bottomRightOffset = Vector3.new(size.X / 2, -size.Y / 2, -size.Z / 2)
local currentBottomRightPosition = partAbove.CFrame.Position + bottomRightOffset
return currentTopLeftPosition, currentBottomRightPosition
end
local function findPartJustBelow(partAbove, partFolder)
local partsListBelow = {}
for _, v in pairs(partFolder:GetChildren()) do
if v:IsA("BasePart") and v.Position.Y < partAbove.Position.Y then
table.insert(partsListBelow, v)
end
end
local partsBelowInRange = {}
local topLeft, bottomRight = getTopLeftAndBottomRightVertices(partAbove)
for _, iterationBox in pairs(partsListBelow) do
local vertices = getVertices(iterationBox)
for _, vertex in pairs(vertices) do
if vertex.X >= topLeft.X and vertex.X <= bottomRight.X and
vertex.Z >= bottomRight.Z and vertex.Z <= topLeft.Z then
table.insert(partsBelowInRange, iterationBox)
break -- No need to check other vertices once one is inside the range
end
end
end
table.sort(partsBelowInRange, function(a, b)
return compFunc(a, partAbove) < compFunc(b, partAbove)
end)
return partsBelowInRange[1]
end
local function findBestPositionForBox(box, pointsList)
local bestPoint = nil
local bestOrientation = nil
local minMagnitude = math.huge
-- First try horizontal placement
for _, rotation in ipairs({0, 90, 180, 270}) do
box.Orientation = Vector3.new(0, rotation, 0)
for _, point in ipairs(pointsList) do
movePartsTopLeftVerticeTo(box, point)
if not isOverlapping(box) and isInContainer(box) then
local magnitude = returnRelativeMagnitude(point)
if magnitude < minMagnitude then
minMagnitude = magnitude
bestPoint = point
bestOrientation = rotation
end
end
end
end
-- If no horizontal placement found, try vertical stacking
if not bestPoint then
for _, rotation in ipairs({0, 90, 180, 270}) do
box.Orientation = Vector3.new(0, rotation, 0)
for _, point in ipairs(pointsList) do
for y = 0, script.Parent.Bounds.Size.Y - box.Size.Y, box.Size.Y + padding do
local adjustedPoint = point + Vector3.new(0, y, 0)
movePartsTopLeftVerticeTo(box, adjustedPoint)
if not isOverlapping(box) and isInContainer(box) then
local magnitude = returnRelativeMagnitude(adjustedPoint)
if magnitude < minMagnitude then
minMagnitude = magnitude
bestPoint = adjustedPoint
bestOrientation = rotation
end
end
end
end
end
end
return bestPoint, bestOrientation
end
local debounce = false
local function reCalculate()
if debounce then return end
debounce = true
local boxes = script.Parent.Pending:GetChildren()
for _, BoxIterate in ipairs(boxes) do
task.wait()
local prevpos = BoxIterate.Position
local bestPoint, bestOrientation = findBestPositionForBox(BoxIterate, pointsList)
if bestPoint and bestOrientation then
warn("Placement found")
BoxIterate.Orientation = Vector3.new(0, bestOrientation, 0)
movePartsTopLeftVerticeTo(BoxIterate, bestPoint)
local vertices = registerVertices(BoxIterate)
for _, v in ipairs(vertices) do
table.insert(pointsList, v)
end
else
BoxIterate.Position = prevpos
end
end
debounce = false
end
local function cleanUp()
pointsList = nil
pointsList = {}
table.insert(pointsList, script.Parent.Bounds.Attachment.WorldCFrame.Position)
for i, v in ipairs(script.Parent.Pending:GetChildren()) do
v.Position = Vector3.new(0, 0, 0)
end
end
reCalculate()
script.Parent.Pending.ChildAdded:Connect(function()
cleanUp()
reCalculate()
end)
Editor is loading...
Leave a Comment