How do I make a tree generator that grows trees?

I would like to make a tree generator similar to the one used in lumber tycoon 2. However I have no idea where to start with CFrame. I’ve looked for tree generators on the developer forum and I don’t like the way the trees generate I want them to grow and not instantly appear. I have tried using Tween Service on the branch of one of the generators and it didn’t turn out well.

2 Likes

First, you should make a plan for how exactly you want the trees to grow. Write it out in great detail (in English or pseudo code).

Some hand-built examples of what you want the final tree to generally look like would also be helpful.

Once you do that, this forum can probably help you brainstorm implementation ideas much more effectively!

I want to have trees grow from random generation while slowly growing bigger over time. So the tree first grows out of the ground and then grows extra branches until its matured.

1 Like

Do you want an animation between stages, or just a switch of models after x amount of time?

1 Like

I would like the trees to not have stages and grow from the ground using CFrame or Tween Service but I have no idea where to start. I don’t want the trees to be pre-made I want a script to generate them. However I don’t know where to start or what documentation I would need to look at.

After A bit of work I’ve made this however I don’t know how to make the branches growing as the tree instantly generates.

local minh, maxh = 20, 70
local size = 14
local width = 3

function generate(position, angle, width, length, level)
	local part = Instance.new('Part')
	part.Anchored = true
	part.Parent = script.Parent.Parent
	part.Size = Vector3.new(width, length, width)
	part.Position = position
	part.Orientation = angle
	part.BrickColor = BrickColor.new("Brown")
	part.Material = Enum.Material.Concrete
	if level >= 3 then
		part.CanCollide = false
	end
	
	-- generate trunks from top
	part.CFrame = (part.CFrame * CFrame.new(0,part.Size.Y/2,0))
	local top = (part.CFrame * CFrame.new(0,part.Size.Y/2,0)).p 
	
	
	if (width > 0.5 and 4 - level > 0) then
		for i=1, math.random(1,5 - level) do
			generate(top, Vector3.new(math.random(minh, maxh), math.random(360), math.random(minh, maxh)), width * 0.8, length * 0.9, level + 1)
		end
	else
		local leaf = Instance.new('Part')
		leaf.Parent = script.Parent.Parent
		leaf.Shape = Enum.PartType.Ball
		leaf.Material = Enum.Material.Grass
		leaf.Name = 'Leaf'
		leaf.Size = Vector3.new(math.random(5,20), math.random(5,20), math.random(5,20))
		leaf.Position = top
		leaf.Anchored = true
		leaf.Color = Color3.fromRGB(0, math.random(100, 150), 0)
		leaf.CanCollide = false
	end
end

generate(script.Parent.Position + Vector3.new(0, -1, 0), Vector3.new(0, 0, 0), width, size, 0)

We can randomly place a part with zero height, and tween it to increase its height and position so that it’s on the ground and growing, perhaps

local tweenService = game:GetService("TweenService")

local function animate(part, trunkEndHeight, tweenInfo1)
	local tween = tweenService:Create(
		part, 
		tweenInfo1, 
		{
			Size = Vector3.new(part.Size.X, trunkEndHeight, part.Size.Z), 
			Position = Vector3.new(part.Position.X, part.Position.Y + trunkEndHeight/2, part.Position.Z)
		}
	)
	
	tween.Completed:Connect(function()
		--[[ 
		animate branches here, 
		maybe add another ".Completed function" for each of those tweens for twigs
		]]
	end)
	
	tween:Play()
end

This may be a good starting point.

I’ve kinda got the code you made implemented however it doesn’t look right the part tween in the center outward.
robloxapp-20221022-1535286.wmv (1.6 MB)

Set the position of the part where it connects with the branch/trunk before it, and then just copy the tween.

But then when do part.Y/2 it does this
robloxapp-20221022-1551570.wmv (2.0 MB)

My current Code if it helps.

math.randomseed(tick())


function dot(c1,c2)
	local m = CFrame.Angles(math.pi/2,0,0)
	return (c1*m).lookVector:Dot((c2*m).lookVector)
end

local tweenService = game:GetService("TweenService")

function animate(part, trunkEndHeight, tweenInfo1, c)
	local tween = tweenService:Create(
		part, 
		tweenInfo1, 
		{
			Size = Vector3.new(part.Size.X, trunkEndHeight, part.Size.Z), 
			Position = Vector3.new(part.Position.X, part.Position.Y + trunkEndHeight/2, part.Position.Z)
		}
	)

	tween.Completed:Connect(function()
		Branch(part,c-1)
	end)

	tween:Play()
end

local leaf_mult = {
	Vector3.new(.8,.4,.8);
	Vector3.new(.7,.55,.7);
	Vector3.new(.85,.75,.85);
	Vector3.new(.65,.55,.65);
	Vector3.new(.75,.5,.9);
}

function Branch(base,c)
	if c <= 0 then
		local leaves = game.ServerStorage.Leaves:Clone()
		local vol = base.Size.x+base.Size.y+base.Size.z
		leaves.Size = leaf_mult[math.random(1,#leaf_mult)]*math.random(vol/3*12,vol/3*14)/2.5
		leaves.CFrame = base.CFrame * CFrame.new(0,base.Size.y/2,0)
		leaves.Parent = base.Parent
	else
		local pos = base.CFrame*CFrame.new(0,base.Size/2,0)
		local height = base.Size.y
		local width = base.Size.x
		local nb = math.random(2,2)
		local r = math.random(45,135)
		local da = math.random(20+55/c,40+40/c)
		local ba = math.random(-da/3,da/3)
		for i=0,nb-1 do 
			local branch = base:Clone()
			local h = height*math.random(95,115)/100
			local new = branch.CFrame * CFrame.new(0,height/2,0) * CFrame.Angles(0,0,math.rad(ba))
			new = new * CFrame.Angles(0,i*(math.pi*2/nb)+r,math.rad(da/2)) * CFrame.new(0,h/2,0)
			local w = dot(new,branch.CFrame)*width*0.9
			branch.Size = Vector3.new(w,0,w)
			
			local timee = h/2
			
			
			local info = TweenInfo.new(timee,Enum.EasingStyle.Linear,Enum.EasingDirection.Out)
			animate(branch,h,info, c)
			branch.CFrame = new
			branch.Parent = base.Parent
		end
	end
end

function GenerateTree(location,complexity,width,height)
	local tree = Instance.new("Model")
	tree.Name = "Tree"
	tree.archivable = false
	tree.Parent = workspace
	local base = game.ServerStorage.Trunk:Clone()
	base.Parent = tree
	base.Size = Vector3.new(width,height,width)
	base.CFrame = CFrame.new(location) * CFrame.new(math.random(-10,10),height/2,math.random(-10,10)) * CFrame.Angles(0,math.rad(math.random(1,360)),0)
	Branch(base,complexity)
	return tree
end

local c,w,h=math.max(1,script.Parent.Complexity.Value),math.max(1,script.Parent.Width.Value),math.max(1,script.Parent.Height.Value)
GenerateTree(script.Parent.CFrame.p-Vector3.new(0,script.Parent.Size.Y,0),c,w,h)
1 Like

What is the script’s fullname, like how do you identify it from game

setup
Complexity is a numberValue of 3
Height is a numberValue of 9
and Width is a numberValue of 2

I got this, and it works for me.

math.randomseed(tick())


function dot(c1,c2)
	local m = CFrame.Angles(math.pi/2,0,0)
	return (c1*m).lookVector:Dot((c2*m).lookVector)
end

local tweenService = game:GetService("TweenService")

function animate(part, trunkEndHeight, tweenInfo1, c)
	local tween = tweenService:Create(
		part, 
		tweenInfo1, 
		{
			Size = Vector3.new(part.Size.X, trunkEndHeight, part.Size.Z), 
			--Position = Vector3.new(part.Position.X, part.Position.Y + trunkEndHeight/2, part.Position.Z)
			CFrame = part.CFrame + part.CFrame.UpVector * (trunkEndHeight/2) -- new
		}
	)

	tween.Completed:Connect(function()
		Branch(part,c-1)
	end)

	tween:Play()
end

local leaf_mult = {
	Vector3.new(.8,.4,.8);
	Vector3.new(.7,.55,.7);
	Vector3.new(.85,.75,.85);
	Vector3.new(.65,.55,.65);
	Vector3.new(.75,.5,.9);
}

function Branch(base,c)
	if c <= 0 then
		local leaves = game.ServerStorage.Leaves:Clone()
		local vol = base.Size.x+base.Size.y+base.Size.z
		leaves.Size = leaf_mult[math.random(1,#leaf_mult)]*math.random(vol/3*12,vol/3*14)/2.5
		leaves.CFrame = base.CFrame * CFrame.new(0,base.Size.y/2,0)
		leaves.Parent = base.Parent
	else
		local pos = base.CFrame*CFrame.new(0,base.Size.Y/2,0)
		local height = base.Size.Y
		local width = base.Size.X
		local nb = math.random(2,2)
		local r = math.random(45,135)
		local da = math.random(20+55/c,40+40/c)
		local ba = math.random(-da/3,da/3)
		for i=0,nb-1 do 
			local branch = base:Clone()
			local h = height*math.random(95,115)/100
			local new = branch.CFrame * CFrame.new(0,height/2,0) * CFrame.Angles(0,0,math.rad(ba))
			new = new * CFrame.Angles(0,i*(math.pi*2/nb)+r,math.rad(da/2)) -- * CFrame.new(0,h/2,0)
			local w = dot(new,branch.CFrame)*width*0.9
			branch.Size = Vector3.new(w,0,w)

			local timee = h/2


			local info = TweenInfo.new(timee,Enum.EasingStyle.Linear,Enum.EasingDirection.Out)
			branch.CFrame = new -- new
			animate(branch,h,info, c)
			-- branch.CFrame = new
			branch.Parent = base.Parent
		end
	end
end

function GenerateTree(location,complexity,width,height)
	local tree = Instance.new("Model")
	tree.Name = "Tree"
	tree.archivable = false
	tree.Parent = workspace
	local base = game.ServerStorage.Trunk:Clone()
	base.Parent = tree
	base.Size = Vector3.new(width,height,width)
	base.CFrame = CFrame.new(location) * CFrame.new(math.random(-10,10),height/2,math.random(-10,10)) * CFrame.Angles(0,math.rad(math.random(1,360)),0)
	Branch(base,complexity)
	return tree
end

local c,w,h=math.max(1,script.Parent.Complexity.Value),math.max(1,script.Parent.Width.Value),math.max(1,script.Parent.Height.Value)
GenerateTree(script.Parent.CFrame.p-Vector3.new(0,script.Parent.Size.Y,0),c,w,h)

Is there a way to make it spawn multiple trees?

I think calling the function GenerateTree multiple times works just fine.

Sorry if I don’t get your question if you have any more dm me because this is an already solved solution.