Script that spawns one item per item in a table isn't quite doing it properly, could use some assistance

Hello, I have a script that is supposed to clone items from storage and spawn them on points that are taken from a table. It works like this: The script takes a folder of spawn points in workspace and adds them each to a table. Then it uses a loop to take each item in another folder full of tools in storage and moves them onto the spawn points. It then removes the point from the table so each spawn point is used only once. Here’s the code:

spawnPlates = game.Workspace.ToolSpawns --folder of the spawn objects that the tools spawn on
tools = game.ServerStorage.Tools --folder of the tools in storage

toolSpawns = {}

for i, v in pairs(spawnPlates:GetChildren()) do
	toolSpawns[i] = v
end

for i, t in pairs(tools:GetChildren()) do
	local newTool = t:Clone()
	newTool.Parent = game.Workspace
	newTool:MoveTo(toolSpawns[i].Position) --i used moveto so I don't have to deal with rotation issues
	table.remove(toolSpawns, i) --i did this so hopefully each spawn point was only used once
	
end	

It works, but only half way. Here’s what it looks like before and after I run it. Also, I just realized typing this out that it doesn’t randomize it like I want it to. How could I randomize it as well?

Before: https://gyazo.com/466dff75b542eefd4eca0d5764085e6d
After: https://gyazo.com/69808e0c39c7849456bb2db43eac26c7

All of the squares should be filled up. I may be forgetting relevant information but if so let me know. Thank you all.

Edit: I forgot to mention that it does throw an error, but it doesn’t make sense to me. https://gyazo.com/915cc71144de996a825e083a077fc5ba

It doesn’t make sense because it says “attempt to index nil with ‘Position’” even though it works. I believe this error is thrown halfway through which causes it to only spawn half the items.

1 Like

According to this, you are looping through all the items. Consequently, I believe your tables are having a mismatch in it’s index value.

So can I ask you to debug further, try printing what is exactly being returned by these functions?

spawnPlates:GetChildren()
tools:GetChildren()

I believe you have more tools than spawn plates. Consequently, if this is the case it is possible to index a nil variable in the second loop like:

local toolSpawns ={1,2}
local tools = {1,2,3,4}

Yeah it might be possible to index tool number 3 within the third index for toolSpawns. Also I don’t think using this is necessary since :GetChildren() already returns an array/table so you shouldn’t need to for loop what it returns.

You could just do this:

toolSpawns = spawnPlates:GetChildren()
1 Like

The issue arises from running table.remove() while the loop is still running. Because that function automatically slides everything down to fill in the gap, some items get skipped.

@JigglyWiggles, are you always spawning in all items? If so, you do not need to remove elements from the table and can just let it get garbage-collected.

1 Like

Instead of looping through the tools, try looping through all spawn plates. I haven’t tested the code so it might not work. If that’s the case, please tell me.

local spawnPlates = game.Workspace.ToolSpawns
local tools = game.ServerStorage.Tools
local toolSpawns = {}

for _, spawnPlate in pairs(spawnPlates:GetChildren()) do
	table.insert(toolSpawns, spawnPlate)
end

for i, spawnPlate in pairs(toolSpawns)
	local tool = tools[i]
	tool.Parent = game.Workspace
	tool:MoveTo(spawnPlate.Position)
end
1 Like

You were right about having more tools, I was off by one. Somehow missed that, thank you. As for the extra debug, here you go:
spawnPlates: https://gyazo.com/66bd9f907e62fc7e4e39fddec8ad7c05
tools: https://gyazo.com/529c8ca89c5108328816fcccc86adbe2

I will try your suggestion, thanks for taking the time to help. Correcting the amount of plates didn’t change much unfortunately though.

The goal is to spawn these items in once per round. I did the remove to hopefully stop it from doubling up but I see why it wouldn’t help. Thank you for your response.

I will definitely try this, thank you. Do you know a way I could incorporate some way to randomize it so it isn’t the same spawn location each time?

Here is a randomised version.

local spawnPlates = game.Workspace.ToolSpawns
local tools = game.ServerStorage.Tools
local toolSpawns = {}

for _, spawnPlate in pairs(spawnPlates:GetChildren()) do
	table.insert(toolSpawns, spawnPlate)
end

local prevTool

for i, spawnPlate in pairs(toolSpawns) do
	local tool
	repeat tool = tools[math.random(1, #tools)] until tool ~= prevTool
	tool.Parent = game.Workspace
	tool:MoveTo(spawnPlate.Position)
	prevTool = tool
end
1 Like

Your first reply definitely worked after adding “do” in the for loop and :GetChildren for the tools variable. Thank you very much! This section still works, but isn’t filling every spawn plate. So each run it is missing a few items, but different than last run so the randomization does work fortunately. I think I may be able to figure it out from here but if you have any ideas I’ll definitely listen, haha. Thank you very much.

Yeah, sorry, I missed those 2 things, haha. I will check why it isn’t filling every spawn plate in studio in about 15 mins and I will get back to you.

No need to apologize, I am just glad I was able to catch it haha. If you need the file or anything to make it easier on you let me know!

It’s fine, I can just create a few parts that act as spawn plates and some random tools. Thanks anyway.

Alright. Thanks again, I appreciate you taking the time to help.

1 Like

Just to make sure, do you want each item to appear only once?

Yes. I have 11 items with 4 different types. 4 of one type, 4 of another, 2 of another, and 1 of another if that makes sense.
https://gyazo.com/96ecc2db1fb065912a3a4ed8cf0b9206

1 Like

Alright, so, this will spawn each item exactly once. E.g. it will spawn 4 coal models, etc.

local spawnPlates = game.Workspace.ToolSpawns
local tools = game.ServerStorage.Tools:GetChildren()
local toolSpawns = {}

for _, spawnPlate in pairs(spawnPlates:GetChildren()) do
	table.insert(toolSpawns, spawnPlate)
end

local prevTools = {}

for _, spawnPlate in pairs(toolSpawns) do
	local tool
	repeat tool = tools[math.random(1, #tools)] until tool and not prevTools[tool]
	local clonedTool = tool:Clone()
	clonedTool.Parent = game.Workspace
	clonedTool:MoveTo(spawnPlate.Position)
	table.insert(prevTools, tool)
end
1 Like

Thank you so much! I have been trying here as well. I did try to use a table as well but couldn’t figure out how to add the object and I also somehow did something to crash studio, lol. Thanks again, I appreciate everything.

1 Like

I’m glad I helped! Good luck with the game you are making!

1 Like

Hey, I hate to bug and bring that back up. I noticed that the script would spawn more than one type of item, for example, 5 coal instead of four and then as a result spawns one less of another item. I spent a lot of time trying to fix it to avoid having to ask again but it’s got me beat. Do you have any ideas?

Hey, I figured it out. I want to tell you just in case you could benefit from it, the least I can do for all your help. So what I ended up doing was first getting it to work properly without the randomization, which you helped me with. So it spawned the proper amount of objects perfectly, just in a predictable pattern. Then I decided instead of choosing a random item from a table, I just randomized the table instead. I had an old shuffle algorithm I used in a project awhile back in Java, and luckily enough it transferred pretty easily into Lua. Here’s the code in case you’re interested:

local spawnPlates = game.Workspace.ToolSpawns
local tools = game.ServerStorage.Tools:GetChildren()
local toolSpawns = {}
local toolsA = {}

for i, v in pairs(tools) do
	
	toolsA[i] = v

end


for i = 1, #tools, 1 do
	local index = math.random(1, #tools)
	local x = toolsA[i]
	toolsA[i] = toolsA[index]
	toolsA[index] = x
	print(x, index, i)
	
end

for _, spawnPlate in pairs(spawnPlates:GetChildren()) do
	table.insert(toolSpawns, spawnPlate)
end

for i, spawnPlate in pairs(toolSpawns) do
	local tool = toolsA[i]
	tool.Parent = game.Workspace
	tool:MoveTo(spawnPlate.Position)
	end