Find a value from a table, that is inside a table

  1. What do you want to achieve? Keep it simple and clear!
    I want to place blocks based on a grid system.
    I have a table named Blocks = {}
    when i place a block i create a new table that is inside the table “Blocks = {}”.

code looks like this

local Blocks = {}
local function roundToStep(pos : Vector3)

	return Vector3.new(math.floor(pos.X/3)*3+1.5,math.floor(pos.Y/3)*3+1.5,math.floor(pos.Z/3)*3+1.5)
end

 
function GridSystem.PlaceBlock(pos,color,material)	
	local block = Instance.new("Part")
	block.Parent = workspace.Blocks
	block.Position = roundToStep(pos)
	block.Size = Vector3.new(3,3,3)
	block.Anchored = true
	block.Color = color
	block.Material = material
	local innerTable = {part=block,position=roundToStep(pos)}
	table.insert(Blocks, t)
end
  1. What is the issue? Include screenshots / videos if possible!
    the issue is that i want to use loops as less as possible to make my game less laggy, I dont want to place a block in a position that already exists in the Block table(to prevent placeing a block on the same position as another block) and to remove the block that has the position associated with the part.
    i prefer to use table.find instead of looping because looping makes the game slower if i want to loop through a lot of blocks.

  2. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

i cant think of a solution without using loops, what if i have 500 blocks in game? i dont want to loop through all the blocks

You need loops for this. But don’t worry; loops are efficient! What you need is an array of arrays.

You need to pick how many rows and columns you want. Then for every X from 1 to #rows, you set grid[x] to {}. Within that for loop, you do another for-loop for Y from 1 to #columns, you set grid[x][y] to the block instance.

-- Function to generate a 2D grid
local function generateGrid(rows, cols)
	local grid = {}

	for x = 1, rows do
		grid[x] = {}  -- Create a new row

		for y = 1, cols do
			grid[x][y] = 0  -- Initialize each cell with a default value. You can spawn a black here.
		end
	end

	return grid
end

-- Example: Create a 3x3 grid
local rows = 3
local cols = 3
local myGrid = generateGrid(rows, cols)

-- Print the generated grid
for i = 1, rows do
	for j = 1, cols do
		print(myGrid[i][j] .. " ")
	end
	print("\n")
end

You’d also need to position every part to Vector3.new(x,0,y). Make sure you also take whatever size the blocks are, and multiply their position by that. If the blocks are 4x4x4, multiply the position by 4. Note that I use y instead of z, since Roblox has Y as the up-axis, you have to use the Z-axis (or you get a grid that goes high up instead of flat on the ground).

this is not what i talk about. i want to see if a value that is inside a table of a table matches another value

Yes, well, if you want to do that, you need to set up your data structures in a way that you can efficiently fetch the data. I don’t understand what you want, but there’s probably an easier way to do it

table.find does the same thing as a for loop.

What’s much, much faster than looping is indexing; it’s constant time. Set the keys of your blocks table as the block’s position and the values the blocks.

local position = Vector3.new(1, 1, 1)
Blocks[position] = block

-- Check if a position is occupied:
if Blocks[position] then
    print("occupied!")
else
    print("we can place here!")
end

-- Get the block from a position
local block = Blocks[position]

-- Remove a block in a given position
Blocks[position]:Destroy() -- Destroy the block instance
Blocks[position] = nil

Looping through a large table is and can be inefficient. I suggest that instead of storing your blocks in an array and searching through it, you can use a table as a dictionary where the keys are the positions of the blocks so you can quickly check if a block exists at a certain position without having to loop through the enter table.

local Blocks = {}

local function roundToStep(pos : Vector3)
	return Vector3.new(math.floor(pos.X/3)*3+1.5,math.floor(pos.Y/3)*3+1.5,math.floor(pos.Z/3)*3+1.5)
end

function GridSystem.PlaceBlock(pos,color,material)
	local roundedPos = roundToStep(pos)
	local posKey = tostring(roundedPos) -- Convert the position to a string to use as a key

	if Blocks[posKey] then
		-- A block already exists at this position
		return
	end

	local block = Instance.new("Part")
	block.Parent = workspace.Blocks
	block.Position = roundedPos
	block.Size = Vector3.new(3,3,3)
	block.Anchored = true
	block.Color = color
	block.Material = material

	Blocks[posKey] = block -- Store the block in the table with the position as the key
end

function GridSystem.RemoveBlock(pos)
	local roundedPos = roundToStep(pos)
	local posKey = tostring(roundedPos) -- Convert the position to a string to use as a key

	local block = Blocks[posKey]
	if block then
		block:Destroy()
		Blocks[posKey] = nil -- Remove the block from the table
	end
end

When you want to place a block, you first check if a block already exists at that position by checking if Blocks[posKey] is not nil. If a block doesn’t exist, you can create a new block and store it in the table with the position as the key. This is so when you want to remove a block, it just destroys the block and removes it from the table.

srry for the long explanation, but this way, you don’t need to loop through the entire table to find a block at a certain position.

Why do i have to do “tostring” and not index them by the position itself?

can i help you @builderIV @ExercitusMortem ??

For Help Contact me

I have another issue related to that one. So i have a part that is the map ( the ground) and i try to index the entire ground as taken region. i have looped the entire size of the map but it somehow places cubes inside the map parts.
this is the code for that

for i,v in pairs(workspace.Map:GetChildren()) do
	for x= -v.Size.X / 2 ,v.Size.X / 2-3,3 do
		for y= -v.Size.Y / 2 ,v.Size.Y / 2-3,3 do
			for z= -v.Size.Z / 2 ,v.Size.Z / 2-3,3 do
				table.insert(Blocks,roundToStep(v.Position+Vector3.new(x,y,z)))
				
			end
		end
	end
end

why it still places blocks inside the map parts that are taken?

Edit: for anyone in the future with this problem, i fixed it by changing the function to:

for i,v in pairs(workspace.Map:GetChildren()) do
	for x= -v.Size.X / 2 ,v.Size.X / 2-3,3 do
		for y= -v.Size.Y / 2 ,v.Size.Y / 2-3,3 do
			for z= -v.Size.Z / 2 ,v.Size.Z / 2-3,3 do
				Blocks[roundToStep(v.Position+Vector3.new(x,y,z))] = v
				
			end
		end
	end
end

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.