Randomly Generating Animated Trees

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();
     }
   }
}

Leave a Reply

Your email address will not be published. Required fields are marked *