//Dynamically growing L-System tree class GrowTree{ float x, y; //Location int num, timer; //Iteration of tree, auto-destruct timer Chromosome id; //Genetic code of tree Seed seed; //Fruit of tree ParticleSystem treePhysics; //Physics object Particle [] particle; //Physical presence of tree nodes Node [] node; //Information about tree nodes Attraction [] suck; //Auto-destruct implementation objects boolean sucking = false; //Tree being destroyed? int fading = 30; //Fade out timer int makeSeed = -1; //Which node is generating a seed (-1 = none) int drawStackSize = 0; //Number of nodes float nodeVelocity = 4.0; //Speed of nodes being fired out GrowTree(int num, float x, float y, Chromosome seedA, Chromosome seedB){ this.x = x; this.y = y; this.num = num; treePhysics = new ParticleSystem(0.0, 0.09); seedA.crossOver(seedB); seedA.mutate(); id = seedA; LSystem lsystem = new LSystem("F", seedA.decode()); lsystem.iterate(2); makeTree(lsystem); seed = new Seed(num); timer = 500 + (int)random(1000); } void draw(){ stroke(0,200,0); for(int i = 0; i < drawStackSize; i++){ if(node[i].active){ if(node[i].seed && fading > 29){ fill(colorTable[num]); } else if (fading > 29){ fill(20, 255, 0); stroke(0, 200, 0); } else { fill(20, 255, 0, (255 / 30) * fading); stroke(0, 200, 0, (255 / 30) * fading); } if(node[i].parent != -1){ strokeWeight(node[i].branchSize); line(particle[i].position().x(), particle[i].position().y(), particle[node[i].parent].position().x(), particle[node[i].parent].position().y()); } strokeWeight(1); ellipse(particle[i].position().x(), particle[i].position().y(), node[i].nodeSize*2, node[i].nodeSize*2); if(node[i].growTimer > -2){ node[i].growTimer--; } if(node[i].growTimer == 0){ growBurst(i); } if(makeSeed == i){ growSeed(makeSeed); } } } if(timer > 0){ timer--; }else if (timer == 0){ timer--; fadeTree(); } if(fading < 30 && fading > -1){ fading--; } treePhysics.tick(); } //Create fruit from a fertile node void growSeed(int i){ if(node[i].nodeSize < 20){ node[i].nodeSize += 0.5; } else { node[i].nodeSize = node[i].branchSize; sound[podBurstSound].stop(); sound[podBurstSound].play(); node[i].seed = false; seed = new Seed(num); seed.activate(particle[i].position().x(), particle[i].position().y()); makeSeed = -1; } } //fires out more nodes from nodes that are "pregnant" (have children) void growBurst(int i){ if(node[i].child != null){ for(int j = 0; j < node[i].child.length; j++){ particle[node[i].child[j]].moveTo(particle[i].position().x(), particle[i].position().y(), 0.0); float xVel = cos(node[node[i].child[j]].angle) * nodeVelocity; float yVel = sin(node[node[i].child[j]].angle) * nodeVelocity; particle[node[i].child[j]].setVelocity(xVel, yVel, 0.0); node[node[i].child[j]].active = true; } } } //Has the tree finished being destroyed? boolean treeSwallowed(){ int j = 0; for(int i = 0; i < drawStackSize; i++){ if(particle[i].position().y() > height){ j++; } } if(j == drawStackSize - 1){ return true; } return false; } //Destroy tree void swallowTree(){ sucking = true; for(int i = 0; i < drawStackSize - 1; i++){ suck[i].turnOn(); } makeSeed = -1; if(seed.active){ seed.treeSucking = true; seed.hopper -= 2; seed.active = false; seed.fading = true; seed.me.makeFixed(); } sound[suckSound].stop(); sound[suckSound].play(); } void fadeTree(){ fading--; makeSeed = -1; if(seed.active){ seed.treeSucking = true; seed.hopper -= 2; seed.active = false; seed.fading = true; seed.me.makeFixed(); } } //generates Nodes and Particles to grow the tree from LSystem class void makeTree(LSystem lsystem){ float angle = PI + HALF_PI; Vector drawStack = new Vector(0); Vector pushPop = new Vector(0); int parent = 0; drawStack.add(new Node(angle, 0.1, 6, -1)); drawStackSize++; for(int i = 0; i < lsystem.tree.length(); i++){ switch(lsystem.tree.charAt(i)){ case 'F': drawStack.add(new Node(angle, 0.5 + random(pushPop.size()*0.1), 7 - constrain(pushPop.size(), 0, 4), parent)); drawStackSize++; parent = drawStackSize-1; break; case 'S': Node seedTemp = new Node(angle, 0.5 + random(pushPop.size()*0.1), 7 - constrain(pushPop.size(), 0, 4), parent); seedTemp.seed = true; drawStack.add(seedTemp); drawStackSize++; parent = drawStackSize-1; break; case '+': angle += angleStep; break; case '-': angle -= angleStep; break; case '[': pushPop.add(new Node(angle, 0.5 + random(pushPop.size()*0.2), 7 - constrain(pushPop.size(), 0, 4), parent)); break; case ']': if(pushPop.size() > 0){ Node temp = (Node)pushPop.remove(pushPop.size()-1); angle = temp.angle; parent = temp.parent; } break; } } particle = new Particle[drawStackSize]; node = new Node[drawStackSize]; node[0] = (Node)drawStack.get(0); node[0].active = true; particle[0] = treePhysics.makeParticle(1.0, x, y, 0.0); particle[0].makeFixed(); for(int i = 1; i < drawStackSize; i++){ node[i] = (Node)drawStack.get(i); if(node[node[i].parent].child != null){ node[node[i].parent].child = append(node[node[i].parent].child, i); } else{ node[node[i].parent].child = new int[1]; node[node[i].parent].child[0] = i; } particle[i] = treePhysics.makeParticle(node[i].weight, x, y, 0.0); } suck = new Attraction[drawStackSize-1]; for(int i = 1; i < drawStackSize; i++){ suck[i-1] = treePhysics.makeAttraction(particle[0], particle[i], 100000, 100.0); suck[i-1].turnOff(); } createSeed(); } //Select a node to grow fruit from void createSeed(){ makeSeed = -1; for(int i = drawStackSize - 1; i > 0; i--){ if(node[i].seed){ while(makeSeed < 0){ for(int j = drawStackSize - 1; j > 0; j--){ if(random(1.0) > 0.7 && node[j].seed){ makeSeed = j; break; } } } } } } } //information about how to draw the tree dynamically is stored in the Node object static class Node{ float angle, weight, branchSize, nodeSize; int parent, growTimer; int [] child; boolean active, seed; Node(float angle, float weight, float size, int parent){ this.angle = angle; this.parent = parent; this.weight = weight; branchSize = size; nodeSize = size; growTimer = 5; active = false; seed = false; } }