Grid placement and collisions

Hello!

I’m working on a system that allows users to design their own shops in a basic 6x6 grid, each tile being 5x5 studs so the whole plot is 30x30 studs. But I’m wondering how I’d go about making collisions or something similar to collisions. All items will fit inside of a 5x5 boundary so I don’t really care about physical collisions, rather I’m looking at a more efficient way to ensure 2 items can’t be on the same grid tile. I want to avoid iterating through the plot’s objects as well. I was thinking of creating a sort of grid system that uses nested tables, something like this, but 5 times in total to account for all 6 rows of items:

tiles = {
    {[1] = nil, [2] = nil, [3] = 'some object'; [4] = nil, [5] = 'some object', [6] = nil}
}

The issue with that is that it seems hacky and a bit unreliable. I’m also considering allowing people to place items on other items, like tables and podiums so ideally whatever system would account for that as well. Any other ideas?

I’d use a 2d map data structure type thing:

function mapSet(map, x, y, value)
    map[x] = map[x] or {0
    map[x][y] = value
end

function mapGet(map, x, y)
    if map[x] then
        return map[x][y]
    end
end

I’d also have some functions for converting a world-space point to “grid space”:

local GRID_SIZE = 6

function round(n, to)
    return math.floor(n/to + 0.5) * to
end

function roundV3(v3, to)
    return Vector3.new(
        round(v3.X, to),
        round(v3.Y, to),
        round(v3.Z, to)
    )
end

function worldToGridSpace(worldPoint)
    return roundV3(worldPoint, GRID_SIZE)
end

function gridToWorldSpace(gridPoint)
    return gridPoint * GRID_SIZE
end

If you put an Attachment inside the Model at each point that should occupy a grid square, you can use that to check if a given grid coordinate is available for placing a given model with a given rotation:

function unique(t)
    local result = {}
    local 
    
end

function getTaggedDescendants(ancestor, tag)
    local result = {}
    for _, d in ipairs(ancestor:GetDescendants()) do
        if TagS:HasTag(d, tag) then
            table.insert(result, d)
        end
    end
    return result
end

function getModelGridPoints(model)
    local gridPointAttachments = getTaggedDescendants(model, "GridPointAttachment")
    local result = {}
    for _, a in ipairs(gridPointAttachments) do
        table.insert(result, worldToGridSpace(a.WorldPosition))
    end
    return result
end

function isModelGridPlacementFree(model)
    for _, gp in ipairs(getModelGridPoints(model)) do
        if mapGet(occupancyMap, gp.X, gp.Z) then
            return false
        end
    end
    return true
end

function placeModelInGrid(model)
    for _, gp in ipairs(getModelGridPoints(model)) do
        mapSet(occupancyMap, gp.X, gp.Z, model) 
    end
end
3 Likes