How to add Trees to Perlin Noise?

I have this code:

local Part = Instance.new("Part") --For cloning
Part.Anchored = true
Part.FormFactor = "Custom"
Part.Size = Vector3.new(4,4,4)
Part.TopSurface = "Smooth"    

local seed = math.random(1, 10e6)
local frequency = 3
local power = 20
local resolution = 256 

for x = 1, resolution do  
	for z = 1, resolution do
        local y1 = math.noise(
            (x*frequency)/resolution,
            (z*frequency)/resolution,
            seed
        )

		local y2 = math.noise(
            (x*frequency*.125)/resolution,
            (z*frequency*.125)/resolution,
            seed
		)
		
		local y3 = math.noise(
            (x*frequency*4)/resolution,
            (z*frequency*4)/resolution,
            seed
        )
        
		local y = (y1*y2*power*power)+y3
		
        local Part = Part:Clone()
        Part.Parent = game.Workspace.Map
        Part.CFrame = CFrame.new(x,y,z)
		
		--[[if math.abs(y2) < .1 then
		    Part.BrickColor = BrickColor.Green()
		elseif math.abs(y2) > .25 then
		    Part.BrickColor = BrickColor.Red()
		else
			Part.BrickColor = BrickColor.Blue()
		end]]
		
	end
end

This code generates a random map using Perlin Noise and Parts. I want to add trees, water, and biomes to this how can I do that?

4 Likes

For trees, assuming you only want trees to spawn where land is, you can user a second perlin noise and layer it on top. For example, after

local Part = Part:Clone()
Part.Parent = game.Workspace.Map
Part.CFrame = CFrame.new(x,y,z)

you can do:

local c = 0.4 -- c is some constant you use to customise how the noise feels
local threshold = 0.1 -- the TreeChance needs to be greater than this to spawn a tree

local TreeChance = math.noise(x * frequency * c / resolution, z * frequency * c / resolution, seed)

if TreeChance > threshold then
    -- Add a tree on top this part
end

Play around with the threshold value and c to get the results you like. Remember math.noise returns a value between -0.5 and 0.5, so don’t let the threshold be 0.5 or greater, otherwise no trees will ever spawn.

2 Likes

If you wanted the water to appear you would check if the block below it spawns below the water level.

local Part = Instance.new("Part") --For cloning
Part.Anchored = true
Part.FormFactor = "Custom"
Part.Size = Vector3.new(4,4,4)
Part.TopSurface = "Smooth"    

local seed = math.random(1, 10e6)
local frequency = 3
local power = 20
local resolution = 256 
local WaterLevel = 0 --We store the level the water spawns below

for x = 1, resolution do  
	for z = 1, resolution do
        local y1 = math.noise(
            (x*frequency)/resolution,
            (z*frequency)/resolution,
            seed
        )

		local y2 = math.noise(
            (x*frequency*.125)/resolution,
            (z*frequency*.125)/resolution,
            seed
		)
		
		local y3 = math.noise(
            (x*frequency*4)/resolution,
            (z*frequency*4)/resolution,
            seed
        )
        
		local y = (y1*y2*power*power)+y3
		
        local Part = Part:Clone()
        Part.Parent = game.Workspace.Map
        Part.CFrame = CFrame.new(x,y,z)
		
		if z%resolution/2==resolution/4 then
			wait(0)
		end
		
		--[[if math.abs(y2) < .1 then
		    Part.BrickColor = BrickColor.Green()
		elseif math.abs(y2) > .25 then
		    Part.BrickColor = BrickColor.Red()
		else
			Part.BrickColor = BrickColor.Blue()
		end]]
		if y+(Part.Size.Y/2)<WaterLevel then -- We check if water is able to spawn.
			print(WaterLevel-y+(Part.Size.Y/2))
			local WaterPart=Part:Clone()
			WaterPart.CanCollide=false -- We set some values to the water.
			WaterPart.Transparency=0.5
			WaterPart.Reflectance=0.1
			WaterPart.Size=Vector3.new(4,WaterLevel-y+(Part.Size.Y/2),1)
			WaterPart.BrickColor=BrickColor.new("Cyan")
			WaterPart.CFrame=CFrame.new(x,y+(WaterLevel-y+(Part.Size.Y/2))/2,z)
			WaterPart.Parent=workspace.Map
		end
	end
end
2 Likes

Thank you this helped me a lot.

1 Like

thanks for the code is this what I am supposed to do?

local c = 0.4 -- c is some constant you use to customise how the noise feels
local threshold = 0.1 -- the TreeChance needs to be greater than this to spawn a tree

local TreeChance = math.noise(x * frequency * c / resolution, z * frequency * c / resolution, seed)

if TreeChance > threshold then
    local Tree = game.Workspace.Tree:Clone()
    Tree.Parent = workspace.Map
    Tree.CFrame = CFrame.new(x,y,z)
end
1 Like

Yes, pretty much, but you would want to set the CFrame of the tree to slightly higher than the block otherwise it will spawn in the same place as the block. Perhpas try this:

Tree.CFrame = CFrame.new(x, y + 5, z) -- using 5 as a constant so all trees will be 5 studs above the block

Or you could calculate the height of the tree and use that:

local TreeHeight = Tree.Size.Y
local PartHeight = Part.Size.Y

-- I split it up here to make it more clear what is happening:
local TreeY = y + PartHeight / 2 + TreeHeight  / 2
-- You take the Y value of the part and add half the height of the part and half the height of the tree.

Tree.CFrame = CFrame.new(x, TreeY, z)

Here is a quick diagram that explains what I did.


In the code you don’t have to have TreeHeight, PartHeight and TreeY as variables, but it helps organise the code and makes it more intuitive to understand.

1 Like

Thanks it works but the trees are spawning next to each other and 3 to 4 trees spawn each time I start the code how can I fix that?

1 Like

Could you upload a screenshot of what is happening?

1 Like

treebug

this

It creates a tree some time later it creates another tree next to it.

I believe there is a problem with your calculation of x and z. When you use perlin noise, you would usually multiply the x and z values by the width and depth of the blocks respectively. Otherwise the blocks would all overlap, and so would the trees. For example, you would do this:

Part.CFrame = CFrame.new(x * Part.Size.X, y, z * Part.Size.Z)
-- ...
Tree.CFrame = CFrame.new(x * Part.Size.X, TreeY, z * Part.Size.Z)

Ideally you would have a constant outside of the for loop with the scale of the blocks,

-- Before for loop
local Scale = Part.Size

-- For loop
for x = 1, resolution do
    for z = 1, resoluation do
        -- ...
        Part.CFrame = CFrame.new(x * Scale.X, y, z * Scale.Z)
        -- ...
        Tree.CFrame = CFrame.new(x * Scale.X, TreeY, z * Scale.Z)
    end
end
1 Like

treebug2

It is making the same thing but with more space

I ran your script on my machine and did not have any problem. Here is some of the output:



(Trees are the brown cylinders and the Parts are the green blocks)


Here is my script (I changed a few things, but I commented on what I chenged):

local Part = Instance.new("Part") --For cloning
Part.Anchored = true
Part.FormFactor = "Custom"
Part.Size = Vector3.new(4,4,4)
Part.TopSurface = "Smooth"
-- Added this to make the part more visible
Part.BrickColor = BrickColor.new("Forest green")

local seed = math.random(1, 10e6)
local frequency = 3
local power = 20
-- Changed to 64 from 256 because my computer cannot handle so many parts
local resolution = 64 

local Scale = Part.Size

-- Changed from "for x = 1, resolution" to "for x = -resolution / 2, resolution / 2" in order to make map centered.
for x = -resolution / 2, resolution / 2 do  
	-- Did the same here for z
	for z = -resolution / 2, resolution / 2 do
        local y1 = math.noise(
            (x * frequency) / resolution,
            (z * frequency) / resolution,
            seed
        )

		local y2 = math.noise(
            (x * frequency * .125) / resolution,
            (z * frequency * .125) / resolution,
            seed
		)
		
		local y3 = math.noise(
            (x * frequency * 4) / resolution,
            (z * frequency * 4) / resolution,
            seed
        )
        
		local y = (y1 * y2 * power * power) + y3
		
        local Part = Part:Clone()
        Part.Parent = game.Workspace.Map
        Part.CFrame = CFrame.new(x * Scale.X, y, z * Scale.Z)

		local c = 0.4 -- c is some constant you use to customise how the noise feels
		local threshold = 0.1 -- the TreeChance needs to be greater than this to spawn a tree
		
		local TreeChance = math.noise(x * frequency * c / resolution, z * frequency * c / resolution, seed)
		
		if TreeChance > threshold then
		    local Tree = game.Workspace.Tree:Clone()
		    Tree.Parent = workspace.Map
			local TreeHeight = Tree.Size.Y
			local PartHeight = Part.Size.Y
			
			local TreeY = y + PartHeight / 2 + TreeHeight  / 2
			
			-- I changed it to Tree.Position instead of Tree.CFrame because the tree is a cylinder, so would spawn flat if I updated the CFrame instead of the position.
			Tree.Position = Vector3.new(x * Scale.X, TreeY, z * Scale.Z)
		end
	end
end

btw there’s no need to do math.random(1, 10e6). Firstly, the lower limit for math.random() is 1 by default, so it’s fine if you just do math.random(10e6). Secondly, you don’t even need an upper limit if you want something completely random. Just doing math.random() and not passing any arguments will generate something random. After you’re done generating, though, you should do math.randomseed(tick() or math.randomseed(os.time()) to reset it.

If it looks a bit unnatural, you can always make it so that no trees can spawn below a certain level (using the y result from the original math.noise) and then set limits to a certain level using the new math.noise.

Edit: oops replied to the wrong person

I found the problem. It was because of the water code. It works without the water code thank you. The water code and the tree code don’t work together.

:sweat_smile:

I think it worked

Please could you mark the post which helped you as the solution so others can find the answer easily. :slight_smile:

1 Like


I got trees to work on my generator but I created a probability function and slapped that onto the generator and added the y offset for the trees (so they would not be in the ground)

2 Likes