I want to get all the Neighbours of a part for example all the parts in green are the Neighbours of the part in red this includes if there are parts above or below it.
how can I get these using scripts. I have tried using raycasting but I could not do it and it seemed performance heavy are there any easier methods? plz help
I need to find the green parts by using some method I did that example manually and it is not just one part it is a grid of 625 parts which i need to find the neighbours of
I thought of an interesting way of doing this using ray casting and some trigonometry:
local origin = part.Position;
local neighbours = {};
local accuracy = 20;
local rayCastIgnoreGroup = "NeighbourCheck";
-- So the ray casting doesn't detect the origin part
local PhysicsService = game:GetService("PhysicsService");
PhysicsService:CreateCollisionGroup(rayCastIgnoreGroup);
PhysicsService:SetPartCollisionGroup(part, rayCastIgnoreGroup);
PhysicsService:CollisionGroupSetCollidable("Default", rayCastIgnoreGroup, false);
local params = RaycastParams.new();
params.FilterType = Enum.RaycastFilterType.Blacklist;
params.IgnoreWater = true;
--Make a circle around the origin
for i = 0, 1, 1 / accuracy do
local degree = math.rad(360 * i);
local scalar = accuracy / 10;
local x = math.cos(degree) * scalar;
local z = math.sin(degree) * scalar;
local getTo = origin + Vector3.new(x, 0, z);
local dir = (getTo - origin).Unit* 100;
local result = workspace:Raycast(origin, dir, params);
if result then
local neighbour = result.Instance;
if not neighbours[neighbour] then
table.insert(neighbours, neighbour);
end;
end;
end;
--Color all neighbours green
for _, neighbour in ipairs(neighbours) do
neighbour.BrickColor = BrickColor.Green();
end;
PhysicsService:SetPartCollisionGroup(part, "Default");
You could run :GetTouchingParts() on the part that you want to find its neighbors. This would return a table of all the parts touching it. However, this may return parts diagonally from the part, so I’d recommend checking that each part shares either and X, or Z value with the current part.
Your code would look something like this:
local part = game.Workspace.Part --change this to the part that you want to get it's neighbors
local Touching = part:GetTouchingParts()
local Neighbors = {}
function GetNeighbors()
for i, Party in pairs(Touching) do
for i,v in pairs(Neighbors) do
Neighbors[v] = nil
end
if Party.Position.X == Part.Position.X or Party.Position.Y == Part.Position.Y then
if Party.Position.Y == Part.Position.Y then
Neighbors.insert(Party)
print(v.Name.." is a neighbor!")
--The part is a neighbor & it has been added to the grand table of neighbors
end
end
end
end
GetNeighbors()
You can then loop through the ‘Neighbors’ table using a for loop to get all the neighbors of the part!
Anyways, I hope this helped, if it did, be sure to mark it as a solution so I can get my third solution, and so people having this problem can find the answer easier!
The easiest way is to keep track of it in the first place.
How are you creating this grid of parts?
If you generate it with a script, finding neighbors becomes easy!
I didn’t test, but something like this:
local parts = {}
local rows = 10
local cols = 10
-- generate a grid and put it in the parts table
for row = 1, rows do
parts[row] = {}
for col = 1, cols do
local p = Instance.new("Part")
p.Size = Vector3.new(1,1,1)
p.Position = Vector3.new(col, 0, row)
p.Anchored = true
p.Parent = workspace
parts[row][col] = p
end
end
local function GetNeighbors(row, col)
local neighbors = {}
if col > 1 then neighbors["left"] = parts[row][col-1] end
if col < cols then neighbors["right"] = parts[row][col+1] end
if row > 1 then neighbors["top"] = parts[row-1][col] end
if row < rows then neighbors["bottom"] = parts[row+1][col] end
return neighbors
end
-- for example, get the neighbors of the part at row 5, column 3:
local neighbors = GetNeighbors(5, 3)
neighbors.left.Color = Color3.new(1,0,0)
neighbors.top.Color = Color3.new(0,1,0)
neighbors.right.Color = Color3.new(0,0,1)
neighbors.bottom.Color = Color3.new(1,1,0)
What you could do instead also is u can raycast the inverse look vector and the look vector and the right vector and the inverse right vector then see if the intersection distance is the size + size.X*0.5 + 0.01
You should also know that if you are trying to get the neighbors cause u trying to do cellular automata
you are much better off for looping those parts into a matrix then doing some matrix math (would be a different devforum post). Ideally we’d run this on the gpu as a vertex shader but you could probably get away with parallel luau since it looks like your scene is small.
local Position = -- Red part
local Up = -- Raycast from Position + Vector3.new(0, 1, 0)
local Down = -- Raycast from Position + Vector3.new(0, -1, 0)
local Left = -- Raycast from Position + Vector3.new(-1, 0, 0)
local Right = -- Raycast from Position + Vector3.new(1, 0, 0)
local Front = -- Raycast from Position + Vector3.new(0, 0, 1)
local Back = -- Raycast from Position + Vector3.new(0, 0, -1)
Raycasts look like this:
local Position = -- Red part
local RayParams = RaycastParams.new()
local Up = workspace:Raycast(Position, Vector3.new(0, 1, 0), RayParams)
u can actualy use find parts in region might be more efficient then itteration over all parts in a folder or the map if its is a huge map and then check the position is close
and then check if the part in the region is redpart.Position.X - partSize.X etc u get the point i think
(assuming part is 1x1x1) stud size
example
local partSize = 1 -- 1 stud change if bigger
local redPart = game.workspace.map.RedPart
local Point1 = Vector3.new((RedPart.Position.X - RedPart.Size.X/2) - partSize,0,(RedPart.Position.Z- RedPart.Size.Z/2) -partSize) -- top left point1 1 stud wider then redpart position
local Point1 = Vector3.new((RedPart.Position.X + RedPart.Size.X/2) + partSize,0,(RedPart.Position.Z+ RedPart.Size.Z/2) +partSize) -- bottom right point2 1 stud wider then redpart position
local Region = Region3.new(Point1,Point2)
local parts = workspace:FindPartsInRegion3(region, redPart) -- ignore redPart
– this return all parts arround the redpart like this X is redpart
[ ][B][ ]
[L][X][R]
[ ][F][ ]
we still have 4 parts too much so we need to filter a bit more specific by checking if part is:
in front (Z-) [F]
in back (Z+) [B]
left (X-) [L]
right (X+) [F]
so we do
for _,Part in pairs(parts) do
if Part.Position == Vector3.new((redPart.Position.X-redPart.Size.X/2)-Partsize/2,redPart.Position.Y,redPart.Position.Z) then
-- left part
elseif Part.Position == Vector3.new((redPart.Position.X+redPart.Size.X/2)+Partsize/2,redPart.Position.Y,redPart.Position.Z) then
--right part
elseif Part.Position == Vector3.new(redPart.Position.X,redPart.Position.Y,(redPart.Position.Z-redPart.Size.Z/2)-partSize/2) then
--front part
elseif Part.Position == Vector3.new(redPart.Position.X,redPart.Position.Y,(redPart.Position.Z+redPart.Size.Z/2)+partSize/2) then
--backpart
end
print(Part.Name)
end
i did not do above or below but its same princable just check y+ y- and also dont forget to change y+ y- on point1 and point2 to include it in the 3d region select