svitoora – 10 Hallow-Eve

Supawat’s Portrait

// 
// 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.

Leave a Reply