It fills mostly correctly, although doesn’t fill the bounding box fully leaving lots of space at the top when it should be generating higher
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
export type ModelOrPart = BasePart | Model
export type FillData = {
ShouldStack: boolean?,
ObjectSize: Vector3,
BoxCFrame: CFrame?,
BoxSize: Vector3,
Padding: Vector2?
}
local Module = {}
function Module.GenerateLayers(Layer: {CFrame}, LayerSize: Vector3, BoxSize: Vector3, ObjectSize: Vector3)
local TotalLayersSize = LayerSize
local Layers = {}
table.insert(Layers, Layer)
repeat
local YPosition = Vector3.new(0, ObjectSize.Y * #Layers, 0)
local NewLayer = {} :: {CFrame}
for _, Position in Layer do
local NewPosition = Position + YPosition
table.insert(NewLayer, NewPosition)
end
TotalLayersSize += YPosition
table.insert(Layers, NewLayer)
RunService.Heartbeat:Wait()
until TotalLayersSize.Y > BoxSize.Y
-- Removing the last layer because it was out of bounds
Layers[#Layers] = nil
return Layers, TotalLayersSize
end
function Module.GenerateLayer(Row: {CFrame}, RowSize: Vector3, BoxSize: Vector3, ObjectSize: Vector3)
local TotalLayerSize = Vector3.new(ObjectSize.X, ObjectSize.Y, RowSize.Z)
local PreviousRowIndexs = {} :: {number}
local Layer = {} :: {CFrame}
-- Generating the first row in the layer
for Index, Position in Row do
table.insert(PreviousRowIndexs, Index)
table.insert(Layer, Position)
end
repeat
local NumberOfRows = #Layer/#Row
local XPosition = Vector3.new((ObjectSize.X * NumberOfRows) + ObjectSize.X, 0, 0)
table.clear(PreviousRowIndexs)
for Index, Position in Row do
local NewPosition = Position + XPosition
table.insert(Layer, NewPosition)
-- Inserting the last index number (the index of the position we just added)
-- to the list of previous row indexs
table.insert(PreviousRowIndexs, #Layer)
end
NumberOfRows = #Layer/#Row
TotalLayerSize += Vector3.new(ObjectSize.X * NumberOfRows, 0, 0)
RunService.Heartbeat:Wait()
until TotalLayerSize.X > BoxSize.X
-- Removing all of the previous row indexs from the layer, as they are outside of the box
for _, Index in PreviousRowIndexs do
table.remove(Layer, Index)
end
return Layer, TotalLayerSize
end
function Module.GenerateRow(BoxCFrame: CFrame, BoxSize: Vector3, ObjectSize: Vector3)
local BoxBottomRight = CFrame.new(BoxCFrame.X + BoxSize.X/2, BoxCFrame.Y - BoxSize.Y/2, BoxCFrame.Z + BoxSize.Z/2)
local TotalRowSize = ObjectSize
local Row = {} :: {CFrame}
-- Putting in the first object position for the row
local BottomRightObjectPosition = CFrame.new(BoxBottomRight.X - ObjectSize.X/2, BoxBottomRight.Y + ObjectSize.Y/2, BoxBottomRight.Z - ObjectSize.Z/2)
table.insert(Row, BottomRightObjectPosition)
repeat
local ObjectPosition = Row[#Row] - Vector3.new(0, 0, -ObjectSize.Z)
table.insert(Row, ObjectPosition)
TotalRowSize += ObjectSize
RunService.Heartbeat:Wait()
until TotalRowSize.Z > BoxSize.Z
-- Removing the last index in the row, so that the row fits in the box
-- And removing the size of one object from the total row size
TotalRowSize = TotalRowSize - ObjectSize
Row[#Row] = nil
return Row, TotalRowSize
end
function Module.FillBoxWithObject(Props: FillData)
return function()
local BoxCFrame = Props.BoxCFrame or CFrame.new(0, 0, 0) :: CFrame
local ShouldStack = Props.ShouldStack
local ObjectSize = Props.ObjectSize
local Padding = Props.Padding
local BoxSize = Props.BoxSize
local Result: any, Result2: any
if Padding then
local PaddingVector2 = Padding/2
local PaddingVector3 = Vector3.new(PaddingVector2.X, 0, PaddingVector2.Y)
ObjectSize = ObjectSize + PaddingVector3
BoxSize = BoxSize - PaddingVector3
end
local Row, RowSize = Module.GenerateRow(BoxCFrame, BoxSize, ObjectSize)
local Layer, LayerSize = Module.GenerateLayer(Row, RowSize, BoxSize, ObjectSize)
if ShouldStack then
local Layers, LayersSize = Module.GenerateLayers(Layer, LayerSize, BoxSize, ObjectSize)
return Layers, LayersSize
else
local ResultTable = {}
table.insert(ResultTable, Layer)
return ResultTable, LayerSize
end
end
end