Hello :D
I am making something on a grid where the state of a part changes based on the ones around it. However I don’t know how I would get the part next to it or nil if there is none. Any ideas?
You could use workspace:GetPartBoundsInBox() with a size slightly larger than the size of your part. However, I wouldn’t necessarily recommend this approach. For efficiency and reliability, you could use your own data structures instead of physics queries.
If the parts are rectangular and the grid as a whole is a rectangle, you could use a simple 2D array of parts (array of arrays or one array with size length * width). If you use code to create the parts, you can add them to the 2D array when you create them.
In addition to this array, you could have a dictionary with parts as keys and grid indices as values (the value could be either a pair of indices or one index that can be converted to a pair of indices). When you add a part to the 2D array, you also add the part as a key and the indices/index as a value in this dictionary.
Assuming that you have an array of arrays of parts, a dictionary containing the two indices for each part as a Vector2 and a function for checking whether a pair of indices is valid, getting the neighbors could look like this:
local function getNeighbors(part: BasePart): {BasePart}
local neighbors: {BasePart} = table.create(4)
local indexVec: Vector2 = indicesForParts[part]
local x: number, y: number = indexVec.X, indexVec.Y
if areCoordsInBounds(x + 1, y) then
table.insert(neighbors, partArray2D[x + 1][y]
end
if areCoordsInBounds(x, y + 1) then
table.insert(neighbors, partArray2D[x][y + 1]
end
if areCoordsInBounds(x - 1, y) then
table.insert(neighbors, partArray2D[x - 1][y]
end
if areCoordsInBounds(x, y - 1) then
table.insert(neighbors, partArray2D[x][y - 1]
end
return neighbors
end
Some follow-up questions:
- What does the
: {BasePart}
part of the code do? - Why are you doing the
indexVec.X + indexVec.Y
? - How would all parts access the same table if variables are only per script?
local function getNeighbors(part: BasePart): {BasePart}
The : {BasePart}
thing is completely optional. It indicates type safety. Basically saying this function will return a table filled with base parts.
Or a simpler example, a function local function myfunction(a: number): boolean
takes in one parameter which is a number and returns a boolean.
local x: number, y: number = indexVec.X + indexVec.Y
I assume this is a typo since it doesnt really make any sense and it would create an error since y
is nil. I assume its supposed to be local x: number, y: number = indexVec.X, indexVec.Y
oh ok, any ideas on the last question?
Yeah, that second one was indeed a typo. Idk what I was thinking when I wrote that plus there .
I’m not sure what you mean by your third question. If you need to access the tables from multiple scripts, you can have the tables in a module script.
I don’t really understand @RoBoPoJu’s answer (since he’s using custom data structures), so I’m going to give my own method that I would use.
local function getClosestPointOnPart(part : BasePart, position : Vector3) : Vector3
-- gets closest point to a position in the bounds of a part
return Vector3.new( math.clamp(position.X, part.Position.X - part.Size.X/2, part.Position.X + part.Size.X/2), math.clamp(position.Y, part.Position.Y - part.Size.Y/2, part.Position.Y + part.Size.Y/2), math.clamp(position.Z, part.Position.Z - part.Size.Z/2, part.Position.Z + part.Position.Z/2) )
end
local function getPartDistance(part1 : BasePart, part2: BasePart) : number
local closestPoint1 : Vector3 = getClosestPointOnPart(part1, part2.Position)
local closestPoint2 : Vector3 = getClosestPointOnPart(part2, closestPoint1)
return (closestPoint2-closestPoint1).Magnitude
end
local threshold = 20 -- studs
local partsArray : {BasePart?} = {} -- this can be any part in workspace or whatever you want to check
function getCloseParts(part : BasePart) : {BasePart}
local closeParts = {}
for _, part2 in ipairs(partsArray) do
if part2 == part then continue end -- dont need to check the part itself
if getPartDistance(part, part2) <= threshold then
table.insert(closeParts, part2)
end
end
end
Unable to test it rn, but it should work, theoretically.
If you want a simpler version that takes less time, you could just get the magnitude of the difference of the two parts’ positions to get the differences from their center, but then it wouldn’t count any large enough part as a neighbor.
Module scripts allow scripts to share data?
Would it work like this?
local module = {}
module.parts = {}
function module.addPart(part)
module.parts.insert(part)
end
function module.getList()
return module.parts
end
return module
If there’s only one grid, the module could look like this for example. I haven’t tested this, though, so I may have made some mistakes in the code.
local PartStorage = {}
local numPartsInColumn: number = --something
local numPartsInRow: number = --something
local partArray2D: {{BasePart}} = table.create(numPartsInColumn)
local indicesForParts: {[BasePart]: Vector2} = {}
local function areCoordsInBounds(rowIndex: number, columnIndex: number): boolean
return rowIndex >= 1 and rowIndex <= numPartsInColumn
and columnIndex >= 1 and columnIndex <= numPartsInRow
end
function PartStorage.addPart(part: BasePart, rowIndex: number, columnIndex: number): ()
partArray2D[rowIndex][columnIndex] = part
indicesForParts[part] = Vector2.new(rowIndex, columnIndex)
end
function PartStorage.getNeighbors(part: BasePart): {BasePart}
local neighbors: {BasePart} = table.create(4)
local indexVec: Vector2 = indicesForParts[part]
local x: number, y: number = indexVec.X, indexVec.Y
if areCoordsInBounds(x + 1, y) then
table.insert(neighbors, partArray2D[x + 1][y]
end
if areCoordsInBounds(x, y + 1) then
table.insert(neighbors, partArray2D[x][y + 1]
end
if areCoordsInBounds(x - 1, y) then
table.insert(neighbors, partArray2D[x - 1][y]
end
if areCoordsInBounds(x, y - 1) then
table.insert(neighbors, partArray2D[x][y - 1]
end
return neighbors
end
for rowIndex: number = 1, numPartsInColumn do
partsArray2D[rowIndex] = table.create(numPartsInRow)
end
return PartStorage