It is a windy day. Let’s plant some things! Add water and fertilizer to make the plant grow. Fertilizer makes the plant grow faster!
Harvest when you are finished growing.
// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Final Project
var tree = [];
var woodlength;
var branchStemX = 340;
//x pos of plant branch stem
var branchStemY = 600;
//y pos of plant branch stem
var fruitAmount = 1;
var fruitSize = 19;
var harvested = 0;
var harvestButton;
var picking = false;
var waterButton;
var watering = false;
var fertilizeButton;
var fertilizing = false;
var wateringCan;
var hand;
var plum;
var leaf;
var compost;
var seedling;
//image names
var count;
//keep track of times a button is clicked
var branchDirection = 1;
//the direction of the recursion tree
var matureness = 9;
//levels of recursion tree
function preload(){
wateringCan = loadImage("http://i.imgur.com/JNvlZzy.png");
hand = loadImage("http://i.imgur.com/7r9pIdV.png");
plum = loadImage("http://i.imgur.com/JEh9AIh.png");
leaf = loadImage("http://i.imgur.com/MDoduCh.png");
compost = loadImage("http://i.imgur.com/Rut3lp4.png");
seedling = loadImage("http://i.imgur.com/BG0X2wj.png");
//preload self drawn images
}
function setup() {
createCanvas(680, 680);
frameRate(7);
harvestButton = createButton('harvest');
harvestButton.position(65, 65);
harvestButton.mousePressed(pick);
//create a button that allows you to harvest fruit
waterButton = createButton('water');
waterButton.position(65, 85);
waterButton.mousePressed(water);
//create a button that allows you to water the plant
fertilizeButton = createButton('fertilize');
fertilizeButton.position(65, 105);
fertilizeButton.mousePressed(fertilize);
//create a button that allows you to fertilize the plant
background(240);
}
function draw() {
noStroke();
fill("SkyBlue");
rect(0,0,680,600);
//render sky
dirt();
//render soil
fill(247,197,51);
ellipse(width - 90, 90, 160,160);
//render sun
push();
translate(width / 4, height - 80);
recursionBranch(matureness, 60, 9);
pop();
push();
translate(width * 3 / 4, height - 80);
recursionBranch(matureness, 60, 9);
pop();
//render background recursion trees
var outcome = "The number of fruit harvested is " + harvested + ".";
textAlign(CENTER);
fill(255);
textSize(16);
text(outcome,width * 4 / 5 , height - 15);
//display the number of fruit harvested
for(var i = 0; i < tree.length; i ++){
tree[i].draw();
stroke(42,27,21);
strokeWeight(6);
line(340, 600, 340,tree[i].branchY);
}
//render whole plant
image(seedling, 265, 550, seedling.width * 0.15, seedling.height * 0.15);
if(picking){
//if the harvest button is pressed change cursor to hand
noCursor();
image(hand, mouseX - 71, mouseY - 15, hand.width * 0.2, hand.height * 0.2);
//shift the new cursor a bit so the finger tip and arrow can align
}
else if(watering){
//if the harvest button is pressed change cursor to watering can
noCursor();
image(wateringCan, mouseX - 50, mouseY - 90, wateringCan.width * 0.3, wateringCan.height * 0.3);
}
else if(fertilizing){
//if the harvest button is pressed change cursor to manure
noCursor();
image(compost, mouseX , mouseY , compost.width * 0.3, compost.height * 0.3);
}
else{
cursor();
}
}
function drawBranch(){
stroke(42,27,21);
strokeWeight(4);
var tipX = this.branchX + this.brachDirection * this.branchLength * cos(this.angle);
var tipY = this.branchY - this.branchLength * sin(this.angle);
line(this.branchX,this.branchY,tipX,tipY);
if(this.fruit){
//if there is fruit, render fruit
ellipseMode(RADIUS);
ellipseMode(CENTER);
fill(124,23,22);
noStroke();
image(plum, this.fruitX - plum.height / 6, this.fruitY - plum.height / 12, plum.width / 3,plum.height / 3);
}
for(var n = 0; n < this.leafNumber; n ++){
push();
translate(this.leaves[n][0],this.leaves[n][1]);
rotate(this.leaves[n][2]);
noStroke();
fill(92,190,66);
image(leaf, 0, 0, leaf.width / 2,leaf.height / 2);
pop();
}
//render leaves
}
function makeBranch(length,x,y){
if ((y / 30) % 2 === 0){
var direction = - 1;
}
else{
direction = 1;
}
//alternate branch directions
var branchAngle = random(0, PI / 3);
//randomize the angle of branch
var leafNumber = Math.floor(random(2, 6));
//randomize the number of leaves on each branch
var leaves = [];
for(var m = 0; m < leafNumber; m ++){
var leafPosition = random(0,length);
leafX = x + direction * leafPosition * cos(branchAngle);
leafY = y - leafPosition * sin(branchAngle);
leafRotation = direction * random(-TWO_PI, TWO_PI);
leaves[m] = [leafX, leafY, leafRotation];
}
//store leaf information in an array
var branches = [];
var s = {
brachDirection: direction,
branchX: x,
branchY: y,
angle: branchAngle,
branchLength: length,
fruit: true,
fruitX: x + direction * length * cos(branchAngle),
fruitY: y - length * sin(branchAngle),
leafNumber: leafNumber,
leaves: leaves,
branches: branches,
draw: drawBranch
}
return s;
}
function mousePressed() {
// fruitAmount = floor(random(0,3));
count += 1;
if(branchStemY > 100){
if(watering & (count > 1)){
branchStemY -= 30;
//grow by 30
woodlength = random(70,130);
//randomize length of branch
tree.push(makeBranch(woodlength,branchStemX,branchStemY));
//push branches on to the array tree
}
if(fertilizing & (count > 1)){
branchStemY -= 30;
woodlength = random(100,150);
//randomize length of branch (fertilizer causes more length)
tree.push(makeBranch(woodlength,branchStemX,branchStemY));
//push branches on to the array tree
}
}
if(picking){
for(var j = 0; j < tree.length; j++){
if(tree[j].fruit){
if(dist(mouseX,mouseY,tree[j].fruitX,tree[j].fruitY) <= fruitSize){
tree[j].fruit = false;
//do not display picked fruit
harvested += 1;
//update the amount of fruit harvested
}
}
}
}
}
function recursionBranch(depth, len, thickness) {
//creates recursive tree with complexity of depth, size of len and boldness of thickness
strokeWeight(thickness);
stroke(50,45,39);
line(0, 0, 0, -len);
//render trunk
push();
translate(0, -len);
if (depth > 0) {
if (depth > 5 ) {
//when complexity is low, thickness decreases faster
rotate(radians(-25));
recursionBranch(depth - 1, len * random ((6 / 7), (8 / 9)),thickness * (3/ 4));
rotate(radians(50));
recursionBranch(depth - 1, len * random ((6 / 7), (8 / 9)),thickness * (3/ 4));
}
else {
//when complexity is low, thickness decreases slower
if(random(1) < 0.75){
//most of the time create one branch
if(branchDirection === -1){
rotate(radians(random(-10,-20)));
recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6 / 7));
branchDirection *= -1;
//alternate branch direction
}
else{
rotate(radians(random(10,20)));
recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6 / 7));
branchDirection *= -1;
//alternate branch direction
}
}
else{
//occasionally create two branches
rotate(radians(-14));
recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6/ 7));
rotate(radians(28));
recursionBranch(depth - 1, len * random ((6 / 7), (3 / 4)),thickness * (6/ 7));
}
}
}
pop();
}
function dirt(){
//render dirt
noStroke();
fill(90,80,60);
rect(0,600,680,80);
image(seedling, 290, 570, seedling.width * 0.1, seedling.height * 0.1);
}
function pick(){
//set to picking mode
picking = true;
watering = false;
fertilizing = false;
}
function water(){
//set to watering mode
watering = true;
picking = false;
fertilizing = false;
count = 0;
}
function fertilize(){
//set to fertilizing mode
fertilizing = true;
watering = false;
picking = false;
count = 0;
}
For the final project, I wanted to make an interactive plant. I have always loved gardening games because of the joy of harvesting decided to make one myself. The number and distribution of leaves and fruit are generated randomly . The extent to which the plant grows will depend on how many times it is watered and fertilized . After you have decided to stop watering, it is harvesting season. The player clicks on a button called “Harvest” and can harvest the fruit by clicking on the fruit and the number of fruit harvested will be displayed on the screen. I also incorporated hand drawn elements in the project to make it more visually pleasing. I scanned the images and uploaded them to imgur to use them in my project.
]]>I chose two projects as reference for my final project.
Extinct is an educational game that allows players to plant either a wild plant or a farm crop by Joe Cutting. The goal of the game is to grow as many seeds as possible through deciding how much water, minerals and sunlight to distribute to growing different parts of the plant. The more seeds you get, the higher your survival rate. The game is interesting in that you have control over your plant and it makes use of scientific knowledge that gives the player something more to take away from the game. Something I wish Cutting did better is that the window is too small for the plant. When the plant gets really tall it goes out of view. The slider bars are also a bit too long.
121 Fake Flowers by W:Mute is a series of 121 computer generated flowers. The artist uses processing to make the flowers and they are all in black and white. What is interesting about the project is that all the flowers have a crystal like structure. Unlike the first project, this is only a simulator of flowers. I thought this project was worth investigating because it could help me generate the leaves and fruit in my game. Is seems that this project has differentiated the petals and the pistils. When I generate my plant I should generate stems and leaves individually. If this project could include more variability, it would be even more interesting.
Links:
]]>
For the final project, I want to make an interactive animation. I have always loved gardening games because of the joy of harvesting and would like to make one myself. The player would be asked to plant one seed in the soil. Then with each attempt to water the plant the seed would grow leaves and eventually fruit of their own. The number and distribution of leaves and fruit would be generated randomly while following the rules of nature like having more leaves than fruit and not cramming too many leaves on one branch. The extent to which the plant grows will depend on how many times it is watered, but watering the plant too much would cause a sudden and unexpected death. The amount of times of watering that would kill the plant is random and different each time. So it is kind of like a betting game: you want to water the plant as much as possible, but it is up to the player to decide when it might be dangerous to keep watering. Keep your current plant or have a dead one. After you have decided to stop watering, it is harvesting season. The player clicks on a button called “Harvest!” and can harvest the fruit by clicking on the fruit and the number of fruit harvested will be displayed on the screen.
]]>// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 11
var seaTurtle;
//create a turtle
function setup() {
createCanvas(600, 400);
background(21,40,71);
seaTurtle = makeTurtle(300,200);
//make a turtle
}
function draw(){
strokeJoin(MITER);
strokeCap(PROJECT);
for(var i = 0; i < 6; i++){
seaTurtle.penUp();
seaTurtle.right(60);
seaTurtle.forward(random(70,200));
var snowFlakeSize = random(1,8);
snowFlake(snowFlakeSize);
}
}
function mouseReleased() {
//when mouse is clicked, redraw 6 snowflakes according to the mouse position
seaTurtle.penUp();
seaTurtle.goto(mouseX,mouseY);
println(mouseX);
for(var i = 0; i < 6; i++){
//draw six snowflakes
seaTurtle.penUp();
seaTurtle.right(60);
seaTurtle.forward(random(70,200));
//randomize how far apart each snowflake is from each other
var snowFlakeSize = random(1,10);
//randomize the size of the snowflakes
snowFlake(snowFlakeSize);
}
}
function snowFlake(a){
seaTurtle.penDown();
//draw snow flake with dimension of a
if(a < 5){
//if a is smaller than 5 fill it with white
seaTurtle.setColor(255);
}
else{
//else fill it with a randomized shade of blue
seaTurtle.setColor(color(random(0,100),random(100,255),255));
}
for(var i = 0; i < 6; i ++){
patternA(a);
}
noLoop();
}
function patternA(a){
//draw branch of snowflake with dimension a
seaTurtle.penDown();
seaTurtle.setWeight(a / 5);
//determine line weight according to the size
seaTurtle.left(30);
seaTurtle.forward(5 * a);
seaTurtle.left(60);
seaTurtle.forward(3 * a);
seaTurtle.left(45);
seaTurtle.forward(4 * a);
seaTurtle.right(45);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(90);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(45);
seaTurtle.forward(3 * a);
seaTurtle.left(135);
seaTurtle.forward(2 * a);
seaTurtle.left(45);
seaTurtle.forward(4 * a);
seaTurtle.right(45);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(90);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(45);
seaTurtle.forward(3 * a);
seaTurtle.left(135);
seaTurtle.forward(2 * a);
seaTurtle.left(30);
seaTurtle.forward(2 * a);
seaTurtle.right(60);
seaTurtle.forward(2 * a);
seaTurtle.right(60);
seaTurtle.forward(2 * a);
seaTurtle.right(60);
seaTurtle.forward(2 * a);
seaTurtle.right(60);
seaTurtle.forward(2 * a);
seaTurtle.left(30);
seaTurtle.forward(2 * a);
seaTurtle.left(135);
seaTurtle.forward(3 * a);
seaTurtle.right(45);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(90);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(45);
seaTurtle.forward(4 * a);
seaTurtle.left(45);
seaTurtle.forward(2 * a);
seaTurtle.left(135);
seaTurtle.forward(3 * a);
seaTurtle.right(45);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(90);
seaTurtle.forward(a / sqrt(2));
seaTurtle.right(45);
seaTurtle.forward(4 * a);
seaTurtle.left(45);
seaTurtle.forward(3 * a);
seaTurtle.left(30);
//draw pattern A
}
function turtleLeft(d) {
this.angle -= d;
}
function turtleRight(d) {
this.angle += d;
}
function turtleForward(p) {
var rad = radians(this.angle);
var newx = this.x + cos(rad) * p;
var newy = this.y + sin(rad) * p;
this.goto(newx, newy);
}
function turtleBack(p) {
this.forward(-p);
}
function turtlePenDown() {
this.penIsDown = true;
}
function turtlePenUp() {
this.penIsDown = false;
}
function turtleGoTo(x, y) {
if (this.penIsDown) {
stroke(this.color);
strokeWeight(this.weight);
line(this.x, this.y, x, y);
}
this.x = x;
this.y = y;
}
function turtleDistTo(x, y) {
return sqrt(sq(this.x - x) + sq(this.y - y));
}
function turtleAngleTo(x, y) {
var absAngle = degrees(atan2(y - this.y, x - this.x));
var angle = ((absAngle - this.angle) + 360) % 360.0;
return angle;
}
function turtleTurnToward(x, y, d) {
var angle = this.angleTo(x, y);
if (angle < 180) {
this.angle += d;
} else {
this.angle -= d;
}
}
function turtleSetColor(c) {
this.color = c;
}
function turtleSetWeight(w) {
this.weight = w;
}
function turtleFace(angle) {
this.angle = angle;
}
function makeTurtle(tx, ty) {
var turtle = {x: tx, y: ty,
angle: 0.0,
penIsDown: true,
color: color(128),
weight: 1,
left: turtleLeft, right: turtleRight,
forward: turtleForward, back: turtleBack,
penDown: turtlePenDown, penUp: turtlePenUp,
goto: turtleGoTo, angleto: turtleAngleTo,
turnToward: turtleTurnToward,
distanceTo: turtleDistTo, angleTo: turtleAngleTo,
setColor: turtleSetColor, setWeight: turtleSetWeight,
face: turtleFace};
return turtle;
}
For this project I wanted to use turtles to draw a complex shape that would be otherwise difficult to achieve through other methods. The shape of a snowflake seemed beautiful and intriguing to me.
In Memoriam Michel Waisvisz was a project done by Nicolas Collins in 2009 to remember the life of Michel Waisvisz who was also a musical composer and inventor of experimental electronic musical instruments. The instrument used in this performance is a simple candle along with a device used to pick up the movement of the flame. The flame controls the oscillators possibly through a temperature sensor.
The way the artist’s artistic abilities are manifested in this project is through his movement of the detector. As the detector moves further or closer to the flame the music changes in pitch and volume. He moves the detector as though it is the baton of a conductor. Another way might be that the artist tuned the device to make it produce the best sounds possible. At the beginning of the performance I did not feel like it was very interesting. However, as the candle started burning out, the flame started flickering which caused the music to be somewhat chaotic. The flickering of the candle and the change in music reminded me of a person struggling for life, refusing to die out and gasping for breath. After a while, the flame dies out as all flames do. All light is gone and the only thing you can hear is silence. The use of a candle in this instrument is very suitable for the artist’s intensions.
Links:
Nicolas Collins: Live At Café Oto February 2010
Feedback Examples: Nicolas Collins
In Memoriam Michel Waisvisz by Nicolas Collins on Youtube
]]>
// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 10
var clowns = [];
//store the clown fish
var terrainSpeed = 0.0005;
var terrainDetail = 0.005;
//used to control sea rocks
function setup() {
createCanvas(600, 400);
// create an initial collection of fish
for (var i = 0; i < 4; i++){
var rx = random(width);
var ry = random(0.8 * height);
clowns[i] = makeClownFish(rx,ry);
}
frameRate(10);
}
function draw() {
background(160);
seaViewer(150,200);
seaViewer(450,200);
seaRocks();
updateAndDisplayClownFish();
removeClownFishThatHaveSlippedOutOfView();
addNewClownFishWithSomeRandomProbability();
fill(41,115,179,0.2);
rect(0,0,width,height);
}
function updateAndDisplayClownFish(){
// Update the fish's positions, and display them.
for (var i = 0; i < clowns.length; i++){
clowns[i].move();
clowns[i].display();
}
}
function removeClownFishThatHaveSlippedOutOfView(){
var clownsToKeep = [];
for (var i = 0; i < clowns.length; i++){
if (clowns[i].fishX + clowns[i].fishWidth > 0) {
clownsToKeep.push(clowns[i]);
}
}
clowns = clownsToKeep; // remember the surviving buildings
}
function addNewClownFishWithSomeRandomProbability() {
// With a very tiny probability, add a new fish to the end.
var newClownLikelihood = 0.009;
if (random(0,1) < newClownLikelihood) {
clowns.push(makeClownFish(width,random(0,0.8 * height)));
}
}
// method to update position of fish every frame
function clownFishMove() {
this.fishX += this.speed;
this.fishY += noise(-this.speed,this.speed);
//randomize speed
}
//draw the clown fish
function clownFishDisplay(){
var fishHeight = this.fishWidth / 2;
noStroke();
fill(255,this.greeness,0);
beginShape();
curveVertex(this.fishX, this.fishY);//head of fish
curveVertex(this.fishX, this.fishY);//head of fish
curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
curveVertex(this.fishX + this.fishWidth / 3, this.fishY - fishHeight * 2 / 3);
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY - (fishHeight / 3));
curveVertex(this.fishX + this.fishWidth, this.fishY);//tail of fish
curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY + (fishHeight / 3));
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
curveVertex(this.fishX + this.fishWidth / 3, this.fishY + fishHeight / 3);
curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY + fishHeight * 1 / 6);
curveVertex(this.fishX, this.fishY);//head of fish
curveVertex(this.fishX, this.fishY);//head of fish
endShape();
//draw body
noStroke();
fill(255);
beginShape();
curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
curveVertex(this.fishX + 0.15 * this.fishWidth, this.fishY - fishHeight * 2 / 5);
curveVertex(this.fishX + this.fishWidth / 3, this.fishY - fishHeight * 2 / 3);
curveVertex(this.fishX + this.fishWidth / 3 + this.headStripe, this.fishY - fishHeight * 1 / 3);
curveVertex(this.fishX + this.fishWidth / 3 - 0.3 * this.headStripe, this.fishY);
curveVertex(this.fishX + this.fishWidth / 3, this.fishY + fishHeight / 3);
curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY + fishHeight * 1 / 6);
curveVertex(this.fishX + 0.1 * this.fishWidth, this.fishY - fishHeight * 1 / 3);
endShape();
//draw head stripe
noStroke();
fill(255);
beginShape();
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY - (fishHeight / 3));
curveVertex(this.fishX + this.fishWidth * 7 / 8 + this.tailStripe, this.fishY - (fishHeight / 6));
curveVertex(this.fishX + this.fishWidth * 7 / 8 + 0.3 * this.tailStripe, this.fishY);
curveVertex(this.fishX + this.fishWidth * 7 / 8 - this.tailStripe, this.fishY + (fishHeight / 6));
curveVertex(this.fishX + this.fishWidth * 7 / 8, this.fishY + (fishHeight / 3));
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY + (fishHeight / 5));
curveVertex(this.fishX + this.fishWidth * 2 / 3 + this.tailStripe, this.fishY);
curveVertex(this.fishX + this.fishWidth * 2 / 3, this.fishY - (fishHeight / 4));
endShape();
//draw tail stripe
fill(0);
ellipse(this.fishX + 0.1 * this.fishWidth, this.fishY - fishHeight * 0.05,fishHeight / 10,fishHeight / 10);
//draw eye
}
function seaViewer(windowX,windowY){
//draw submarine outside window
strokeWeight(3);
stroke(90);
rectMode(CENTER);
noFill();
rect(windowX,windowY,240,340,80,80,80,80);
fill("LightBlue");
noStroke();
rect(windowX,windowY,200,300,70,70,70,70);
nail(windowX,windowY - 160, 12);
nail(windowX,windowY + 160, 12);
nail(windowX - 110,windowY, 12);
nail(windowX + 110,windowY, 12);
nail(windowX - 100,windowY - 120, 12);
nail(windowX + 100,windowY + 120, 12);
nail(windowX - 100,windowY + 120, 12);
nail(windowX + 100,windowY - 120, 12);
}
//draw nails on window
function nail(nailX, nailY, nailSize){
noStroke();
fill(100);
ellipse(nailX,nailY,nailSize,nailSize);
var screwlength = nailSize / (4 * sqrt(2));
strokeWeight(1);
stroke(0);
line(nailX - screwlength,nailY - screwlength,nailX + screwlength,nailY + screwlength);
line(nailX - screwlength,nailY + screwlength,nailX + screwlength,nailY - screwlength);
}
//draw sea rocks
function seaRocks(){
fill(11,20,61);
noStroke();
push();
translate(0,80);
//move down 80
beginShape();
vertex(0, height);
for (var x = 0; x < width; x++) {
var t = (x * terrainDetail) + (millis() * terrainSpeed) * 3 / 4;
var y = map(noise(t), 0,1, 0, height );
vertex(x, y);
}
vertex(width, height);
endShape();
pop();
}
//create an object to store clownfish
function makeClownFish(birthLocationX,birthLocationY) {
var clownFish = {
fishX: birthLocationX,
//x location of fish
fishY: birthLocationY,
//y location of fish
fishWidth: random(30,120),
//width of fish
greeness: random(30,140),
//G value of the fish body color
move: clownFishMove,
//move the fish
speed: -random(0,4),
//randomize horizontal speed
display: clownFishDisplay,
//draw fish
headStripe: random(-8,8),
//randomize the stripe on head
tailStripe: random(-5,5)
//randomize the stripe on tail
}
return clownFish;
}
In this project I wanted to depict a view of marine life in front of a submarine window. The camera is following the submarine from outside. At first I only changed the color and size of the fish, then I realized I could make variations in the patterns of the fish as well.
]]>
Nova Jiang is a Chinese artist that builds interactive installations based in Los Angeles. She has a degree in Media Arts from UCLA and has been doing work that makes the audience relate with her artwork in one way or another.
The project Ideogenetic Machine that started in 2001 and is still ongoing generates a 4 page graphic novel in real time based on the photos taken of viewers and previously drawn news events. The artist uses a camera to capture visitors who are eager to pose and use their creativity to make a graphic novel that features them as the protagonist. Then, she uses customized software to make those photos into a line drawing and integrate them into the partially finished story randomly. Finally, the visitor can add dialogue into the text boxes left blank based on their own interpretation. Jiang adds to the database of drawings continuously, converting her views of current events into drawings that are then used to make each customized graphic novel.
What is interesting to me about this project is the importance of the viewer in making the comic. The amount of interactivity surpasses many other interactive installations. Another interesting thing is that the project is always up to date. I admire Jiang for her perseverance in adding drawings of current events into the system and making it a story that matters.
Links
Ideogenetic Machine on Vimeo
Ideogenetic Machine on Youtube
]]>// Simin Li
// Section C
// siminl@andrew.cmu.edu
// Project 9 in objects
var d = 9;
//side length of each rhombus
var portrait;
//the image to be preloaded
var cubes = [];
//create array named cubes
var m = 0;
//index of the array cubes
var pointt = [];
//create an array to store coordinates not yet used
var getIndex = 0;
//the index of the number of array[2]
for(var k = -45; k < 62; k++){
for(var n = -45; n < 62; n++){
pointt.push([k,n]);
}
}
//create a 2D array called pointt and store arrays of length of 2 using a for loop in it
function preload(){
portrait = loadImage("http://i.imgur.com/QPplgCrg.jpg");
//load image
}
function setup() {
createCanvas(600, 600);
background(0);
portrait.resize(610,610);
//resize the original image to fit on a 800 by 800 canvas
//when resized to 600 by 600 rgb values of border points are undefined
//so it is resized to 610 by 610
portrait.loadPixels();
//load pixels
frameRate(100);
}
function draw() {
colorMode(RGB);
var gapY = d * sqrt(3) / 2;
//differnce of x values between two adjacent hexagon left corners
var gapX = d * 3 / 2;
//differnce of y values between two adjacent hexagon left corners
IndexofCoordinate = floor(random(0,pointt.length));
//randomly select an array inside the array pointt
var j = pointt[IndexofCoordinate][0];
//j is the first element of the selected array
//assign a random value to j so it draws in a random hexagon slot
var i = pointt[IndexofCoordinate][1];
//i is the second element of the selected array
//assign a random value to i so it draws in a random hexagon slot
var X = 18 + gapX * j;
var Y = gapY * j;
cubeX = X + gapX * i;
//x coordinates of hexagon
cubeY = Y - gapY * i;
//y coordinates of hexagon
color1 = portrait.get(cubeX + d , cubeY + 3);
//color of bottom left rhombus is determined by a pixel in that rhombus
color2 = portrait.get(cubeX + d , cubeY - 3);
//color of top left rhombus is determined by a pixel in that rhombus
color3 = portrait.get(cubeX + d + 3, cubeY);
//color of right rhombus is determined by a pixel in that rhombus
cubes[m] = new Cube(cubeX,cubeY,color1,color2,color3);
cubes[m].draw();
m ++;
pointt.splice(IndexofCoordinate, 1);
//remove the coodinate that has already been used so it doesn't redraw in the same slot
println(IndexofCoordinate);
}
function rhombus(x,y,angle){
//create function that draws rhombus at x,y
//rotate by angle
var h = d * sqrt(3)/2;
//height of rhombus
push();
translate(x, y);
rotate(radians(angle));
shearX(radians(30));
//shifts a rectangle into a parallelogram by 30 degrees
rect(0, 0, d, h);
pop();
}
function Cube(x,y,color1,color2,color3){
//creates object that combines three rhombuses into a cube at x,y
//each filled by color1,color2,color3
this.x = x;
this.y = y;
this.color1 = color1;
this.color2 = color2;
this.color3 = color3;
this.draw = function(){
noStroke();
fill(color1);
rhombus(x,y,0);//draws bottom left rhombus
fill(color2);
rhombus(x,y,300);//draws top left rhombus
push();
translate(1.50 * d, d * sqrt(3)/2);
fill(color3);
rhombus(x,y,240);//draws right rhombus
pop();
}
}
I wanted controlled randomness in my portrait because I don’t like overlapping geometric shapes so I decided to use my wallpaper project as a template and treated the tiles as “slots” I could fill in randomly. I wanted to practice my objects so in the end I organized my code using an object. After I finished, I realized that a lot of spots were being reused so it is takes a long time to fill in the last few slots. So with help, I decided to create a 2d array that stored all of the coordinates that have not been used yet. After I drew that cube I removed it from the array.
I thought the post MREYES-LOOKINGOUTWARDS-SYNCRO MAIL – UNCONSCIOUS COLLECTIVE by Mreyes posted in 2016 was interesting so I decided to look into this project. This website by Lisa Jevbratt sends a photo paired with a word to a user and documents the content of every sent email. Like the author, I also enjoyed seeing the interaction between people. Not only did this project show the relation between the sender and the receiver, but also the people who were being tied together through the same images.
I think the author did a great job of explaining the possible underlying algorithms of the work, but to be more specific, each image is generated using the last 24 numbers of each user’s IP address. Unfortunately, the website is no longer running, but if it was, according to Mreyes’s assumption that the software randomly chooses images from Google and the fact that every two minutes, humans take more photos than ever existed in total 150 years ago, you would see the change of images on the web through the years. In this sense, this project is like a time capsule that adds something every day.
Mreyes was not sure of the artist’s intentions, but in my opinion, the artist is trying to make the point that many events are not causal, they are synchronistic, or coincidences in time which is a romantic thought.
Links:
]]>
James George was the first artist in residence at Microsoft Research in Seattle and had a background as a computer scientist. He describes himself as an artist and makes software that documents the world in unconventional ways. He and two others founded Specular studios and aims to apply design to emerging technology. Exquisite City was a project done in April 2015 that documented places using photography and built a 3D model of an imaginary city by putting these “building blocks” together. This project was inspired by Exquisite Corpses, surrealist drawings of people made by multiple artists. Some of his other works include Clouds, an interactive installation done by openFrameworks and Specular Portraits that changes the lighting on geometric portraits. What is most interesting about George’s is that he is trying to change from “an artist making things that reflect his vision of the world, to an artist making tools that allow other people to see as they see.” as said by Kevin Slavin. One way that George presented successfully was by playing videos to further explain his description of the project. A lot of art, especially good art is unconventional and the only way to make people understand is showing them.
Here is James George speaking at Eyeo Festival 2015:
Links:
James George at the Eyeo Festival
Other works by James George:
Exquisite City
Clouds
]]>