Untitled
unknown
lua
a month ago
9.0 kB
4
Indexable
Never
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)
Leave a Comment