How do I stop randomly generated parts from spawning inside of each other?

Okay, so, I made this script that generates a certain amount of trees in random positions, a random leaf colour, and a random size.

It works pretty well, but sometimes this will happen:

I don’t mind the leaves going inside each other, but sometimes the tree trunks go inside each other, but that doesn’t look good and isn’t realistic.

I am trying to stop the tree trunks from going inside of each other.
Here is the script(Note:I am not the best of scripting, I have only been doing it for a few months.):

For context this is how the tree is laid out:
Tree

local ServerStorage = game:GetService("ServerStorage")
local Tree = ServerStorage:WaitForChild("Tree")
local Button = workspace.Part.ClickDetector


local function treeGenerated()
	local TreeProperties = {
		Position = Vector3.new(math.random(0,512), math.random(5,10), math.random(0,512));
		LeaveSize = Vector3.new(math.random(5,10), math.random(5,10), math.random(5,10));
		LeaveColor = {BrickColor.new("Forest green"), BrickColor.new("Sea green"), BrickColor.new("Camo")}
}
	local NewTree = Tree:Clone()
	NewTree.Parent = workspace
	NewTree.Wood.Position = TreeProperties.Position - Vector3.new(256, 0, 250)
	NewTree.Leave.Position = TreeProperties.Position - Vector3.new(256, 0, 250) + Vector3.new(0,11,0)
	NewTree.Leave.Size = TreeProperties.LeaveSize + Vector3.new(0,0.5,0)
	local RandomLeaveColour = math.random(1, #TreeProperties.LeaveColor)
	NewTree.Leave.BrickColor = TreeProperties.LeaveColor[RandomLeaveColour]
end

Button.MouseClick:Connect(function()
for i = 0, 1000, 1 do
	treeGenerated()
	end
end)

This is the game(if you want to see it):

Press the gray block near spawn to generate 1000 trees, you can press it multiple times if you want.

2 Likes

add a script that detects if a tree trunk is touching another tree trunk and then delete one of the trunks

2 Likes

I would add this script in ever tree.wood.

local ServerStorage = game:GetService("ServerStorage")
local Tree = ServerStorage:WaitForChild("Tree")
local Button = workspace.Part.ClickDetector

local function treeGenerated()
	local TreeProperties = {
		Position = Vector3.new(math.random(0,512), math.random(5,10), math.random(0,512));
		LeaveSize = Vector3.new(math.random(5,10), math.random(5,10), math.random(5,10));
		LeaveColor = {BrickColor.new("Forest green"), BrickColor.new("Sea green"), BrickColor.new("Camo")}
}
	local NewTree = Tree:Clone()
	NewTree.Parent = workspace
	NewTree.Wood.Position = TreeProperties.Position - Vector3.new(256, 0, 250)
	NewTree.Leave.Position = TreeProperties.Position - Vector3.new(256, 0, 250) + Vector3.new(0,11,0)
	NewTree.Leave.Size = TreeProperties.LeaveSize + Vector3.new(0,0.5,0)
	local RandomLeaveColour = math.random(1, #TreeProperties.LeaveColor)
	NewTree.Leave.BrickColor = TreeProperties.LeaveColor[RandomLeaveColour]
end

script.Parent.Touched:Connect(function(h)
       if h.Parent.Name == "Wood" then
            treeGenerated()
script.Parent.Parent:Destroy()
      else
      script:Destroy()

end)
1 Like

You could use GetTouchingParts after spawning in a tree. You could then loop through the table returned by GetTouchingParts and destroy the tree model if the trunk is touching another part named "Wood".
Example:

local ServerStorage = game:GetService("ServerStorage")
local Tree = ServerStorage:WaitForChild("Tree")
local Button = workspace.Part.ClickDetector


local function treeGenerated()
	local TreeProperties = {
		Position = Vector3.new(math.random(0,512), math.random(5,10), math.random(0,512));
		LeaveSize = Vector3.new(math.random(5,10), math.random(5,10), math.random(5,10));
		LeaveColor = {BrickColor.new("Forest green"), BrickColor.new("Sea green"), BrickColor.new("Camo")}
	}
	local NewTree = Tree:Clone()
	NewTree.Parent = workspace
	NewTree.Wood.Position = TreeProperties.Position - Vector3.new(256, 0, 250)
	NewTree.Leave.Position = TreeProperties.Position - Vector3.new(256, 0, 250) + Vector3.new(0,11,0)
	NewTree.Leave.Size = TreeProperties.LeaveSize + Vector3.new(0,0.5,0)
	local RandomLeaveColour = math.random(1, #TreeProperties.LeaveColor)
	NewTree.Leave.BrickColor = TreeProperties.LeaveColor[RandomLeaveColour]
	for i,v in pairs(NewTree.Wood:GetTouchingParts()) do
		if v.Name == "Wood" then
			NewTree:Destroy()
			break
		end
	end
end

Button.MouseClick:Connect(function()
for i = 1, 1000 do
	treeGenerated()
	end
end)
6 Likes

You could possibly have a table which contains all the position and if you find the same position in the table generate a new position.

I realise this wouldn’t help the issue of trees touching each other but at least it stops the trees from being in the same spot

EDIT: Nvm use @ND_B7 Method

make a block where you would like the trees to spawn, put it over the area, then spawn the trees randomly from these blocks

I’m confused, the script that I made is inside of ServerScriptService, but thanks for the help.

Yes but if he wanted exactly 1000 trees then many would be missing because they would be deleted.

In that case, @SpacialEthanRB would need to use a while loop instead of a for loop. The function would have to return whether the tree was successfully generated or not, so that the loop only moves on to the next tree if the current one was successfully generated.
Code:

local ServerStorage = game:GetService("ServerStorage")
local Tree = ServerStorage:WaitForChild("Tree")
local Button = workspace.Part.ClickDetector


local function treeGenerated()
	local TreeProperties = {
		Position = Vector3.new(math.random(0,512), math.random(5,10), math.random(0,512));
		LeaveSize = Vector3.new(math.random(5,10), math.random(5,10), math.random(5,10));
		LeaveColor = {BrickColor.new("Forest green"), BrickColor.new("Sea green"), BrickColor.new("Camo")}
	}
	local NewTree = Tree:Clone()
	NewTree.Parent = workspace
	NewTree.Wood.Position = TreeProperties.Position - Vector3.new(256, 0, 250)
	NewTree.Leave.Position = TreeProperties.Position - Vector3.new(256, 0, 250) + Vector3.new(0,11,0)
	NewTree.Leave.Size = TreeProperties.LeaveSize + Vector3.new(0,0.5,0)
	local RandomLeaveColour = math.random(1, #TreeProperties.LeaveColor)
	NewTree.Leave.BrickColor = TreeProperties.LeaveColor[RandomLeaveColour]
	for i,v in pairs(NewTree.Wood:GetTouchingParts()) do
		if v.Name == "Wood" then
			NewTree:Destroy()
			return false
		end
	end
	return true
end

Button.MouseClick:Connect(function()
	local i = 1
	while true do
		if i >= 1000 then break end
		local success = treeGenerated()
		if success then
			i = i + 1
		end
	end
end)

Is there a foolproof way to do this without destroying the tree?