//
// Supawat Vitoorapakorn
// Svitoora@andrew.cmu.edu
// Section E
//
// Hallow-Eve: Recusively generate a forest of Sakura.
// Using a Lindenmayer system, each plant grows towards the sun.
var terrainSpeed = 0.0005;
var terrainDetail = 0.005;
var w = 480;
var h = 480;
var x_create = w + 50;
// Global Variable
var PLANT;
var PLANTS = [];
var segment_l = h * .1;
var r = h * .05 * .5;
var common_ratio = .618033 //Golden Ratio
var food;
// Recursively generates a plant model
var max_i = 5; // Max iteration depth
var cur_i = 0;
var DRAW_i = 0; // DRAW's iteration depth
///// MODEL /////
// Creates the sun for plants to grow towards
function food_create(x = w / 2, y = -h * 2) {
this.x = x;
this.y = y;
}
// Creates plants node. Nodes that have .child are branches,
// and nodes without .child are leaves.
function create_plant_node(x, y) {
this.x = x;
this.y = y;
this.x0 = this.x;
this.y0 = this.y;
this.child = [];
this.x1 = null;
this.y1 = null;
}
// Grows plant by making plant seek sunlight
function grow(plant, cur_i) {
// Using the golden ratio, plant's branch size is a geometric sequence
l = segment_l * (common_ratio ** (cur_i))
// Randomly generate the next node via reducing
// distance from plant ro sun
do {
angleMode(DEGREES);
if (cur_i == 0) {
angle = 5;
theta = random(-90 - angle, -90 + angle);
} else {
theta = random(0, 360);
}
plant.x1 = plant.x0 + (l * cos(theta));
plant.y1 = plant.y0 + (l * sin(theta));
d_new = dist(plant.x1, plant.y1, food.x, food.y)
d_old = dist(plant.x0, plant.y0, food.x, food.y)
}
// Keep generating until the new distance is less than the current one
while (d_new > d_old)
plant.child = [];
// Randomly decide how many children(branches) a node should have
for (var x = 0; x < random(1, 4); x++) {
plant.child.push(new create_plant_node(plant.x1, plant.y1));
}
}
// Recursively generates plant
function generate_plant(PLANT, cur_i, max_i) {
// Break Base
if (cur_i == max_i) {
return
// Continue case
} else {
grow(PLANT, cur_i);
cur_i++;
for (i in PLANT.child) {
generate_plant(PLANT.child[i], cur_i, max_i)
}
}
}
///// DRAW /////
// Recursively draws plant
function draw_PLANT(plant, DRAW_i) {
DRAW_i++; // Increases DRAW's Depth counter
stroke(255 * .3)
strokeCap(SQUARE);
strokeWeight((h * .0125) * (common_ratio ** DRAW_i))
// Break case: Flowers
// If node has no children; draw leaf.
// print(plant);
if (plant.child == []) {
fill(255, 255, 255);
ellipse(plant.x, plant.y, (2 / 600) * w, (2 / 600) * w);
return
} // If node has chldren; draw branches
else {
r = r ** common_ratio;
if (plant.child.length != 0) {
for (i in plant.child) {
line(plant.x, plant.y,
plant.child[i].x, plant.child[i].y)
draw_PLANT(plant.child[i], DRAW_i);
}
}
}
}
///// SETUP /////
function setup() {
createCanvas(w, h);
background("#ff9900");
food = new food_create();
// Row Cols Controller
num_tree = 3;
num_row = 4;
y_pos = 0;
// Translates Row and Col of Trees
// Rows
y_pos = w * .75;
PLANT = new create_plant_node(x_create, y_pos);
generate_plant(PLANT, cur_i, max_i);
PLANTS.push(PLANT);
}
// Recursively move each node of tree
function tree_move(tree) {
D = -1;
tree.x += D;
tree.x0 += D;
tree.x1 += D;
// Break
if (tree.child == []) {
return
} else {
// Recurse
for (i in tree.child) {
tree_move(tree.child[i]);
}
}
}
// To reduce system overload
function kill_plant() {
if (PLANTS.length > 5) {
PLANTS.shift();
}
}
var time = 1;
function draw() {
time += 1
background("#ff9900");
kill_plant();
// Represent and move trees
for (index in PLANTS) {
tree_move(PLANTS[index])
draw_PLANT(PLANTS[index], DRAW_i);
}
// Create new tree every modulo time
if (time % 160 == 0) {
PLANT = new create_plant_node(x_create, y_pos);
generate_plant(PLANT, cur_i, max_i);
PLANT.time = time;
PLANTS.push(PLANT);
}
// Draw Floor
fill(255 * .3);
rect(0, h * .75, w, h);
}
The most difficult part of this project was to get each node of the tree to move. Recursively creating the tree was easy because I had already done it before, but doing a DOF search for each node and moving it along was a challenge because it was hard to keep track of variables. I also didn’t expect recursive trees to be so computationally expensive to make, therefore I can only limit it to a few moving ones.