Tree Generator
Video on this: https://youtu.be/Jsdn2Vx-Elk
​
Feel free to implement this code into your projects or use the results in a game or video as long as you follow these rules. Feel free to feature this in videos.
I programmed all of this myself in the unity game engine as I am accustomed to it and it allowed me to render stuff on the screen easily especially given that I am only 13 at the time of making the project and only 2 proper years of coding experience, it really helps.
​
​
DO NOT: Publish a commercial or paid application that has the tree generation code without permission
DO NOT: Publish a free, non commercial application where the main or only focus is on the tree generation from this code without credits or with permission
DO NOT: Claim you made the tree generator code
DO NOT: Sell any of the un-edited results of this code for any money
​
YOU MAY: Give out un-edited results as long as it is for free
YOU MAY: Sell SIGNIFICANTLY EDITED results
YOU MAY: Make an application that uses this code if it is non-commercial and is free with permission
You May: Use the RESULTS of this code in any project as long as there are credits to this page or to 'Gaming Tardigrade'
​
Enough said, here is the unity code:
TreeGenerator:
​
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TreeGenerator : MonoBehaviour
{
[Header("ScriptableObject")]
public TreeGeneratorPrefab prefab;
[Header("Other Settings")]
public bool generateOnStart;
public float sizeTimeser;
public enum TreeNodeState {Null, Trunk, Branch, BranchEnd, Leaf};
[Header("other")]
public Renderer rendererObject;
private Texture2D texture;
[Header("Quantities")]
private float pixelLeafChance;
private float waterGrowthChance;
private int waterItterations = 1;
private Gradient leafColours;
private Gradient TrunkColours;
private int TreePixelSizeX, TreePixelSizeY;
private TreeGeneratorNode[,] Nodes;
private TreeGeneratorNode[] BranchEndNodes;
private TreeData currentTree;
private void DecodeScriptabeObject()
{
pixelLeafChance = prefab.pixelLeafChance;
TreePixelSizeX = prefab.TreePixelSizeX;
TreePixelSizeY = prefab.TreePixelSizeY;
waterGrowthChance = prefab.waterGrowthChance;
waterItterations = prefab.waterItterations;
leafColours = prefab.leafColours;
TrunkColours = prefab.TrunkColours;
}
void Start()
{
if(generateOnStart)
GenerateTree();
}
public void GenerateTree()
{
DecodeScriptabeObject();
float[] ratio = TScriptUt.GetRatio(TreePixelSizeX, TreePixelSizeY);
rendererObject.transform.localScale = new Vector3(ratio[0] * sizeTimeser, 1f, ratio[1] * sizeTimeser);
texture = new Texture2D(TreePixelSizeX, TreePixelSizeY);
Nodes = new TreeGeneratorNode[TreePixelSizeX,TreePixelSizeY];
for (int x = 0; x < TreePixelSizeX; x++)
{
for (int y = 0; y < TreePixelSizeY; y++)
{
// if (x == TreePixelSizeX / 2 && y == TreePixelSizeY / 2) continue;
Nodes[x,y] = new TreeGeneratorNode();
Nodes[x, y].colour = new Color(0, 0, 0, 0);
Nodes[x, y].state = TreeNodeState.Null;
Nodes[x,y].positionX = x;
Nodes[x,y].positionY = y;
}
}
for (int i = 0; i < TreePixelSizeY / 3; i++)
{
Nodes[TreePixelSizeX / 2, i / 2].state = TreeNodeState.Trunk;
Nodes[TreePixelSizeX / 2, i / 2].colour = TrunkColours.Evaluate(Random.Range(0f, 1f)); ;
}
for (int i = 0; i < waterItterations; i++)
{
AddWater();
}
AddLeaves();
ApplyTexture();
}
public void AddLeaves()
{
foreach (TreeGeneratorNode node in Nodes)
{
List<TreeGeneratorNode> Neighbours = GetNeighbours(node);
int neighbourCount = 0;
foreach (TreeGeneratorNode neighbour in Neighbours)
{
if (neighbour.state != TreeNodeState.Null && neighbour.state != TreeNodeState.Trunk)
{
neighbourCount++;
}
}
if (neighbourCount >= 1 && Random.Range(0f,1f) <= pixelLeafChance)
{
node.colour = leafColours.Evaluate(Random.Range(0f, 1f));
}
}
}
public void AddWater()
{
bool[] isWater = new bool[TreePixelSizeX];
bool[] waterToClear = new bool[TreePixelSizeX];
for (int i = 0; i < TreePixelSizeX; i++)
{
float value = 1;
if (value >= TreePixelSizeX / 2 && value <= TreePixelSizeX)
{
value = TreePixelSizeX;
}
isWater[i] = Random.Range(0f,1f * value) >= 0.7f;
waterToClear[i] = false;
}
for (int y = TreePixelSizeY -1; y > 0; y--)
{
bool exists = false;
foreach (bool b in isWater)
{
if (b)
{
exists = true;
break;
}
}
if (!exists)
break;
List<TreeGeneratorNode> nodesForLogging = new List<TreeGeneratorNode>();
for (int x = 0; x < TreePixelSizeX; x++)
{
if (Nodes[x, y].state != TreeNodeState.Trunk && isWater[x])
{
if (Random.Range(0f, 1f) >= waterGrowthChance)
continue;
List<TreeGeneratorNode> neighbours = GetNeighbours(Nodes[x, y]);
bool HasNeighbour = false;
foreach (TreeGeneratorNode node in neighbours)
{
if (node.state != TreeNodeState.Null)
{
HasNeighbour = true;
break;
}
}
if (HasNeighbour)
{
nodesForLogging.Add(Nodes[x, y]);
Nodes[x, y].colour = TrunkColours.Evaluate(Random.Range(0f, 1f));
waterToClear[x] = true;
}
}
else
{
waterToClear[x] = true;
}
}
if (nodesForLogging.Count > 0)
{
foreach (TreeGeneratorNode n in nodesForLogging)
{
n.state = TreeNodeState.Branch;
}
}
for (int i = 0; i < TreePixelSizeX; i++)
{
if (waterToClear[i])
isWater[i] = false;
}
}
}
public void ApplyTexture()
{
for (int x = 0; x < TreePixelSizeX; x++)
{
for (int y = 0; y < TreePixelSizeY; y++)
{
TreeGeneratorNode targetNode = Nodes[x, y];
texture.SetPixel(x,y, targetNode.colour);
}
}
texture.filterMode = FilterMode.Point;
texture.wrapMode = TextureWrapMode.Clamp;
texture.Apply();
rendererObject.sharedMaterial.mainTexture = texture;
}
public List<TreeGeneratorNode> GetNeighbours(TreeGeneratorNode node)
{
List<TreeGeneratorNode> neighbours = new List<TreeGeneratorNode>();
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0)
continue;
int checkX = node.positionX + x;
int checkY = node.positionY + y;
if (checkX >= 0 && checkX < TreePixelSizeX && checkY >= 0 && checkY < TreePixelSizeY)
{
neighbours.Add(Nodes[checkX, checkY]);
}
}
}
return neighbours;
}
}
​
​
TreeGeneratorPrefab:
​
using UnityEngine;
[CreateAssetMenu()]
public class TreeGeneratorPrefab : ScriptableObject
{
public Gradient leafColours;
public Gradient TrunkColours;
public int TreePixelSizeX, TreePixelSizeY;
public int waterItterations;
[Range(0f, 1f)]
public float pixelLeafChance;
[Range(0f, 1f)]
public float waterGrowthChance;
}
​
​
TreeGeneratorNode:
​
using UnityEngine;
public class TreeGeneratorNode
{
public Color colour;
public TreeGenerator.TreeNodeState state;
public int positionX;
public int positionY;
}