Randomly Generating Trees
Trees are found all around the world yet none look quite exactly the same. Games like The Long Dark or Firewatch both take place in environments filled with trees. Having different styles for trees is crucial in games like these to avoid making the game look dull or boring. Including different variations of certain things can be very important in making a game feel more professional whether the variations be randomly generated or from a man-made set. To start off with creating trees with code you have to figure out what you could compare them to, this happens to be what’s known as fractals. Fractals are immensely complicated abstract objects that typically resemble objects found in nature. The image below shows a fractal that looks similar to a tree. Here’s a program that generates random fractal-like trees. This program creates trees based off of random values such as: the number of break-offs, the number of branches that grow from each break-off, how much the branches spread apart, etc. It then creates new branches based off of these values and once it hits the end of the branch it adds a “leaf”. You can test it down below or find it at: https://www.ktbyte.com/projects/project/73151. [raw] [/raw] After going through the example you should try changing the variables up to create different styles of trees or possibly trying to create other plants like flowers, bushes, etc. This could be done by editing the colors, changing the branch sizes and other small tweaks like these.Tree tree; float frame = 0; void setup() { size(400,600); strokeCap(SQUARE); tree = new Tree(); } void draw() { frame += 0.05; background(90, 130, 250); tree.trunk.display(tree.x, height); fill(255); textAlign(CENTER); text("Click to create a new tree!", width / 2, 30); } void mousePressed() { tree = new Tree(); } class Tree { float x = width / 2; //Where the base of the tree is int branchesAtBreak = (int) random(2, 5); //How many branches at each break int numberOfBreaks = (int) random(4, 6); //How many breaks float trunkWidth = random(1, 4) * (float) numberOfBreaks; //Width of trunk float branchSpread = random(1, 7); //How much should the branches spread out float branchSplay = random(0.2, 1.1); //The lower the number the shorter the outer branches are float branchLengthMulti = random(0.2, 0.95); //How much branches shrink length wise each break float branchWidthMulti = random(0.4, 0.7); // Same as above except with width float breezeStrength = random(1)+3; //How strong is the "breeze" that sways the tree float leafSize = random(15, 30); //Size of the leaves Branch trunk = new Branch(this, PI, 0, height/random(2,3), trunkWidth, branchesAtBreak, numberOfBreaks); //Creates tree trunk and provides tree info to the rest of the tree } class Branch { boolean endOfBranch = false; float xpos, globalAngle, localAngle, branchLength; int branchesAtBreak, numberOfBreaks; float trunkWidth; Branch[] branches = new Branch[0]; Tree tree; float waveOffset = random(-1, 1); Branch(Tree tempT, float tempGA, float tempLA, float tempL, float tempTW, int tempBAB, int tempNOB) { tree = tempT;branchesAtBreak = tempBAB;numberOfBreaks = tempNOB;trunkWidth = tempTW;globalAngle = tempGA;localAngle = tempLA;branchLength = tempL; if (numberOfBreaks == 0) { endOfBranch = true; //Lets tree know once it has hit the end of the branch } else { endOfBranch = false; branches = new Branch[branchesAtBreak]; float minimumAngle = -((tree.branchSpread*(branchesAtBreak-1))/2); //Calculates minimum angle of a branch for (int i=0; i<branches.length;i++) { float thisBranchAngle = ((tree.branchSpread * i) + minimumAngle + random(-0.5,0.5))*(tree.branchSplay/numberOfBreaks); //Randomizes angle of branch float thisBranchLenDiv = (float) abs(i - ((tree.branchesAtBreak - 1 ) / 2)) + 1; //Number that length of branches are divided by branches[i] = new Branch(tree, globalAngle + thisBranchAngle, thisBranchAngle, // (branchLength*tree.branchLengthMulti)/thisBranchLenDiv, // Adds child branch trunkWidth * tree.branchWidthMulti, branchesAtBreak, numberOfBreaks-1); // } } branchLength *= random(0.2, 1.2); //Randomizes trunk length after finishing all other branches } void display(float startX, float startY){ float breeze = (sin(frame+waveOffset)/branchLength)*tree.breezeStrength; //Calculates the offset caused by the breeze float endX = (float)(startX + (sin((globalAngle+breeze))*branchLength)); //Determines the end position of the branch float endY = (float)(startY + (cos((globalAngle+breeze))*branchLength)); // /\ //Draws Branches pushMatrix(); stroke(83, 49, 24); strokeWeight(trunkWidth + 1); line(startX,startY,endX,endY); popMatrix(); //Draws all child branches for (int i = 0; i < branches.length; i++){ branches[i].display(endX,endY); } //Draws leaves once you hit the end of the branch if (branches.length == 0) { pushMatrix(); stroke(143, 221, 44); strokeWeight(1); fill(143, 221, 44); ellipse(endX,endY,tree.leafSize,tree.leafSize); popMatrix(); } } }