Monday, July 06, 2009

Forest I

spArrayList trees; 
int NUMGENERATIONS = 5;

void setup() {
  size(800, 400);
  trees = new spArrayList(20);
}

void draw() {
  Tree t;
  if(trees.size() == 0) {
    trees.add(new Tree(new Coordinate(width/2, height - 10)));
  }
  background(133,221,254);
  strokeWeight(10);
  stroke(187,209,66);
  line(0, height - 5, width, height - 5);
  for(int i=0; i < trees.size(); i++) {
    t = (Tree)trees.get(i);
    t.draw();
    if(t.dead && t.colorOffset > 200) {
      trees.remove(i);
    }
  }
}

void mousePressed() {
  trees.clear();
}

class spArrayList {
  Object[] contents;
  boolean[] inUse;
  int count;
  
  spArrayList(int s) {
    contents = new Object[s];
    inUse = new boolean[s];
    count = 0;
  }
  
  void add(Object o) {
    for(int i=0; i < inUse.length; i++) {
      if(inUse[i] == false) {
        contents[i] = o;
        inUse[i] = true;
        count++;
        break;
      }
    }
  }
  
  void remove(int l) {
    int i = 0, j = 0;
    while(i < l) {
      if(inUse[j]) {
        i++;
      }
      j++;
    }
    inUse[j] = false;
    count--;
  }
  
  Object get(int l) {
    int i = 0, j = 0;
    while(i < l) {
      if(inUse[j]) {
        i++;
      }
      j++;
    }
    return contents[j];
  }
  
  int size() {
    return count;
  }
  
  void clear() {
    for(int i=0; i < inUse.length; i++) {
      inUse[i] = false;
    }
    count = 0;
  }
}

class Tree {
  spArrayList branches = new spArrayList(50);
  spArrayList fruits = new spArrayList(50);
  float x, y;
  boolean dead = false;
  int colorOffset = 0;
  
  Tree(Coordinate c) {
    this.x = x;
    this.y = y;
    branches.add(new Branch(this, c, -1, 0, 1));
  }
  
  void draw() {
    Branch b;
    Fruit f;
    for(int i = 0; i < branches.size(); i++) {
      b = (Branch)branches.get(i);
      b.grow();
      b.draw();
    }
    for(int i = 0; i < fruits.size(); i++) {
      f = (Fruit)fruits.get(i);
      f.grow();
      f.draw();
      if(f.dead) {
        fruits.remove(i);
      }
    }
    if(dead == false && random(1000) > 998) {
      colorOffset = 10;
      dead = true;
    }
    if(dead) {
      colorOffset += 3;
    }
  }
}

class Branch {
  Coordinate s, e;
  float dy, dx;
  int l = 0, g, fruitSize = 1;
  boolean growing = true, madeFruit = false;
  Tree p;
  
  Branch(Tree parent, Coordinate start, float dy, float dx, int generation) {
    p = parent;
    s = start;
    e = new Coordinate(s.x, s.y);
    this.dy = dy;
    this.dx = dx;
    g = generation;
  }
  
  void grow() {
    if(growing) {
      float pDiv;
      e.x += dx;
      e.y += dy;
      l++;
      pDiv = (float)g * sq((float)l/100);
      if(random(1) < pDiv) {
        if(g < NUMGENERATIONS) {
          p.branches.add(new Branch(p, e, random(-3, -1), random(-3, 0), g+1));
          p.branches.add(new Branch(p, e, random(-3, -1), random(0, 3), g+1));
        }
        growing = false;
      }
    }
  }
  
  void draw() {
    strokeWeight(NUMGENERATIONS-g);
    stroke(143 - p.colorOffset, 119 - p.colorOffset, 91 - p.colorOffset, 255 - p.colorOffset);
    line(s.x, s.y, e.x, e.y);
    if(growing == false && g == NUMGENERATIONS && madeFruit == false) {
      p.fruits.add(new Fruit(e));
      madeFruit = true;
    } else if(growing == false && g > 2) {
      noStroke();
      fill(42 - p.colorOffset, 191 - p.colorOffset, 26 - p.colorOffset, 255 - p.colorOffset);
      ellipse(e.x, e.y, 5, 10);
    }
  }
}

class Fruit {
  float dy = 0;
  Coordinate l;
  int fruitSize = 1;
  boolean dead = false;
  
  Fruit(Coordinate location) {
    l = new Coordinate(location.x, location.y);
  }
  
  void grow() {
    if(fruitSize < 7) {
      fruitSize++;
    } else {
      if(random(1) > 0.9) {
        dy = 10;
      }
    }
    if(l.y < height - 10) {
      l.y += dy;
    } else if(l.y >= height - 10) {
      if(random(1) > 0.1) {
        dead = true;
      } else {
        trees.add(new Tree(l));
      }
    }
  }
  
  void draw() {
    noStroke();
    fill(184,22,40);
    ellipse(l.x, l.y, fruitSize, fruitSize);
  }
}
  
class Coordinate {
  float x, y;
  
  Coordinate(float x, float y) {
    this.x = x;
    this.y = y;
  }
}

info info

submitted by: jon_stutters
views: 1903
First (fairly crude) attempt at a generative forest. So much more that I want to do with this - animals, nutrients, weather, more realistic fruiting - but I thought at this point it was interesting enough to share.

Tags: trees, generative, simulation, forest

comments comment

loading loading...

 

Add a comment: