//Alana Wu
//ID: alanawu
//Final Project
var buildings = [];
var buildings2 = [];
var buildings3 = [];
var counts = 0;
var fireCount = 0;
var myParticles = [];
var nParticles = 800;
var group = true;
function setup()
{
createCanvas(600, 600);
rectMode(CENTER);
ellipseMode(CENTER);
frameRate(10);
for (var i = 0; i < 10; i++) //makes original buildings in 1st layer
{
var rx = random(width);
buildings[i] = makeBuilding(rx);
}
for (var j = 0; j < 8; j++) //makes original buildings in 2nd layer
{
var ax = random(width);
buildings2[j] = makeBuilding2(ax);
}
for (var k = 0; k < 8; k++)//makes original buildings in 3rd layer
{
var bx = random(width);
buildings3[k] = makeBuilding3(bx);
}
for (var i = 0; i < nParticles; i++) //makes original particles
{
var rx = random(width);
var ry = random(230, 280);
var p = makeParticle(rx, ry, 0, 0);
p.bHardBoundaries = true;
p.damping = 0.99;
myParticles[i] = p;
}
}
var desiredSeparation = 50;
var separationFactor = 0.01;
function separate(p) //applies force that separates particles
{
// rule applies if separation is < desired separation,
// apply an opposing force to achieve greater separation
// opposing force grows as the separation becomes less
for (var i = 0; i < myParticles.length; i++)
{
var boid = myParticles[i]; // get each other particle
var d = dist(p.px, p.py, boid.px, boid.py);
if (d > 1 & d < desiredSeparation)
{
// divide by distance so that the total force is 1
var fx = (p.px - boid.px) / d;
var fy = (p.py - boid.py) / d;
// scale force by (desiredSeparation - d), which
// is 0 at desiredSeparation and grows as distance
// becomes less
var factor = (desiredSeparation - d) * separationFactor;
p.addForce(fx * factor, fy * factor);
}
}
}
function draw()
{
background(0, 0, counts*5);
fill (150, 0, 0, 200);
rect (300, 240, width, 80); //red rect behind 1st layer of buildings
fill (75, 0, 0, 200);
rect(300, 175, width, 50); //red rect behind 2nd layer of buildings
updateAndDisplayBuildings();
removeBuildingsThatHaveSlippedOutOfView();
addNewBuildingsWithSomeRandomProbability();
fill (100, 0, 0);
rect (300, 450, width, 400);
for (var i = 0; i < myParticles.length; i++) //applies separate to the particles
{
var ithParticle = myParticles[i];
ithParticle.fx = 0;
ithParticle.fy = 0;
separate(ithParticle);
}
for (var i = 0; i < myParticles.length; i++)
{
var p = myParticles[i]
p.update(); // update all locations
p.draw(); // draw all particles
}
oilRig(200, 400); //draws oil rig in foreground
smokeClouds(110, 90, 30, 25, 240); //draws smoke clouds coming out of oil rig chimneys
smokeClouds(170, 90, 30, 25, 230);
smokeClouds(230, 90, 30, 25, 220);
smokeClouds(140, 90, 30, 25, 200);
smokeClouds(200, 90, 30, 25, 140);
if (fireCount > 1) //draws fires in different spots on oil rig as you click the mouse
{
push();
translate (180, 200);
fire (100, 100, 1);
pop();
}
if (fireCount > 2)
{
push();
translate (0, 320);
fire(100, 100, 1);
pop();
}
if (fireCount > 3)
{
push();
translate (20, 230);
fire(100, 100, 1);
pop();
}
if (fireCount > 4)
{
push();
translate (250, 260);
fire(100, 100, 1);
pop();
}
if (fireCount > 5)
{
push();
translate (110, 240);
fire(100, 100, 1);
pop();
}
if (fireCount > 6)
{
push();
translate (150, 290);
fire(100, 100, 1);
pop();
}
if (fireCount > 7)
{
push();
translate (-70, 290);
fire(100, 100, 1);
pop();
}
if (fireCount > 8)
{
push();
translate (235, 330);
fire(100, 100, 1);
pop();
}
if (fireCount > 9)
{
push();
translate (-400, 100);
fire(100, 100, 5);
pop();
}
if (fireCount > 10)
{
push();
translate (-200, 100);
fire(100, 100, 5);
pop();
}
if (fireCount > 11)
{
push();
translate (0, 100);
fire(100, 100, 5);
pop();
}
drawButton();
if (fireCount > 12) //world goes boom once you click enough times. Draws final screen
{
fill(255, 0, 0);
rect(300, 300, width, height);
textSize(140);
stroke(255);
fill(0);
strokeWeight(8);
text("BOOM", 85, 300);
textSize(12);
noStroke();
text("RIP humanity.", 15, 580);
}
}
function fire(x, y, size)
{
fill (255, 0, 0); //red flame
beginShape();
vertex((x + 10)*size, y*size);
vertex((x + 20)*size, (y - 20)*size);
vertex((x + 23)*size, (y - 50)*size);
vertex(x*size, (y - 100)*size);
vertex((x - 4)*size, (y - 60)*size);
vertex((x - 12)*size, (y - 80)*size);
vertex((x - 24)*size, (y - 50)*size);
vertex((x - 16)*size, (y - 20)*size);
endShape();
push(); //orange flame
fill (255, 130, 0);
translate(size*32, size*28);
beginShape();
vertex((x + 10)*size*.7, y*size*.7);
vertex((x + 20)*size*.7, (y - 20)*size*.7);
vertex((x + 23)*size*.7, (y - 50)*size*.7);
vertex(x*size*.7, (y - 100)*size*.7);
vertex((x - 4)*size*.7, (y - 60)*size*.7);
vertex((x - 12)*size*.7, (y - 80)*size)*.7;
vertex((x - 24)*size*.7, (y - 50)*size*.7);
vertex((x - 16)*size*.7, (y - 20)*size*.7);
endShape();
pop();
push(); //yellow flame
fill (255, 255, 0);
translate(size*65, size*55);
beginShape();
vertex((x + 10)*size*.4, y*size*.4);
vertex((x + 20)*size*.4, (y - 20)*size*.4);
vertex((x + 23)*size*.4, (y - 50)*size*.4);
vertex(x*size*.4, (y - 100)*size*.4);
vertex((x - 4)*size*.4, (y - 60)*size*.4);
vertex((x - 12)*size*.4, (y - 80)*size)*.4;
vertex((x - 24)*size*.4, (y - 50)*size*.4);
vertex((x - 16)*size*.4, (y - 20)*size*.4);
endShape();
pop();
}
function smokeClouds(x, y, w, h, col)
{
fill (col);
ellipse (x + 35, y - 40, w*1.5, h*1.5);
ellipse (x + 20, y - 45, w*1.5, h*1.5);
ellipse (x + 50, y - 55, w*1.5, h*1.5);
ellipse (x + 25, y - 60, w*1.5, h*1.5);
ellipse (x, y, w, h);
ellipse (x + 10, y, w, h);
ellipse (x, y + 10, w, h);
ellipse (x - 12, y, w, h);
ellipse (x - 5, y - 12, w - 10, h - 10);
ellipse (x - 20, y + 40, w/2, h/2);
ellipse (x - 23, y + 35, w/2, h/2);
ellipse (x - 15, y + 35, w/2, h/2);
}
function updateAndDisplayBuildings()//moves the buildings and redraws them
{
for (var i = 0; i < buildings3.length; i++)
{
buildings3[i].move();
buildings3[i].display();
}
for (var i = 0; i < buildings2.length; i++)
{
buildings2[i].move();
buildings2[i].display();
}
for (var i = 0; i < buildings.length; i++)
{
buildings[i].move();
buildings[i].display();
}
}
function removeBuildingsThatHaveSlippedOutOfView() //gets rid of building objects we no longer can see
{
var buildingsToKeep = [];
for (var i = 0; i < buildings.length; i++)
{
if (buildings[i].x + buildings[i].breadth > 0)
{
buildingsToKeep.push(buildings[i]);
}
}
buildings = buildingsToKeep;
var buildings2ToKeep = [];
for (var i = 0; i < buildings2.length; i++)
{
if (buildings2[i].x + buildings2[i].breadth > 0)
{
buildings2ToKeep.push(buildings2[i]);
}
}
buildings2 = buildings2ToKeep;
var buildings3ToKeep = [];
for (var i = 0; i < buildings3.length; i++)
{
if (buildings3[i].x + buildings3[i].breadth > 0)
{
buildings3ToKeep.push(buildings3[i]);
}
}
buildings3 = buildings3ToKeep;
}
function addNewBuildingsWithSomeRandomProbability()
{
var newBuildingLikelihood = 0.02;
if (random(0,1) < newBuildingLikelihood)
{
buildings.push(makeBuilding(width));
buildings2.push(makeBuilding2(0));
buildings3.push(makeBuilding3(width));
}
}
function buildingMove()
{
this.x += this.speed;
}
function buildingDisplay()
{
if (this.color == 0)
{
fill (255, 0, 255, this.opacity); //light green
}
else if (this.color == 1)
{
fill(255, 255, 0, this.opacity); //yellow
}
else if (this.color == 2)
{
fill(255, 0, 0, this.opacity); //red
}
else if (this.color == 3)
{
fill(0, 0, 255, this.opacity); //blue
}
else if (this.color == 4)
{
fill (255, 0, 120, this.opacity); //orange
}
else if (this.color == 5)
{
fill (0, 255, 0, this.opacity); //green
}
push();
translate(this.x, this.layer);
rect(0, -this.bHeight/2, this.breadth, this.bHeight);
pop();
}
function makeBuilding(birthLocationX)
{
var bldg = {x: birthLocationX,
breadth: random(30, 80),
speed: -1.0,
color: int(random(6)),
opacity: 250,
bHeight: random(30, 150),
layer: 250,
move: buildingMove,
display: buildingDisplay}
return bldg;
}
function makeBuilding2(birthLocationX)
{
var bldg2 = {x: birthLocationX,
breadth: random(30, 80),
speed: 1.0,
color: int(random(5)),
opacity: 155,
bHeight: random(50, 150),
layer: 200,
move: buildingMove,
display: buildingDisplay}
return bldg2;
}
function makeBuilding3(birthLocationX)
{
var bldg3 = {x: birthLocationX,
breadth: random(30, 80),
speed: -1.0,
color: int(random(5)),
opacity: 100,
bHeight: random(50, 150),
layer: 150,
move: buildingMove,
display: buildingDisplay}
return bldg3;
}
function oilRig (x, y) //all dirty colors
{
var bounce = 0;
var dy = -1;
fill (200);
noStroke();
rect (x - 120, y + 100, 50, 80); //base columns
rect (x + 120, y + 100, 50, 80);
push();
translate (0, bounce);
bounce += dy;
if (bounce > 5 || bounce < -5)
{
dy*= -1;
}
fill (130);
for (var j = 0; j < 5; j++)
{
rect (x + 100 - j*30, y - 75 - j*20, 100, 40);
}
fill (200);
var diff = -110;
for (var i = 0; i < 5; i++)
{
rect (x + diff, y - 160, 15, 200);
diff += 30;
}
fill (60);
rect (x - 90, y - 110, 100, 120);
fill (80);
rect (x + 30, y - 90, 100, 70);
fill (150);
rect (x - 120, y + 50, 30, 20);
rect (x + 120, y + 50, 30, 20);
fill (100);
rect (x, y, 350, 100); //big rectangle
rect (x - 60, y - 80, 100, 60);
fill (50);
rect (x - 100, y + 15, 280, 50);
rect (x + 100, y - 40, 250, 40);
rect (x + 100, y - 100, 20, 80);
rect (x + 60, y - 100, 20, 80);
rect (x + 20, y - 100, 20, 80);
fill (80);
rect(x, y - 20, 400, 25);
fill (150);
rect (x, y, 400, 10);
pop();
}
function drawButton() //click here button in bottom right corner
{
fill(0);
rect (530, 550, 90, 40);
fill(255);
text("CLICK HERE", 493, 553);
noStroke();
}
function mousePressed() //counts for background color and fires drawn
{
counts ++;
if (mouseX > 485 & mouseX < 575 && mouseY > 530 && mouseY < 570)
{
fireCount ++;
}
}
// Update the position based on force and velocity
function particleUpdate()
{
if (this.bFixed == false) {
this.vx *= this.damping;
this.vy *= this.damping;
this.limitVelocities();
this.handleBoundaries();
this.px += this.vx;
this.py += this.vy;
}
}
// Prevent particle velocity from exceeding maxSpeed
function particleLimitVelocities()
{
if (this.bLimitVelocities) {
var speed = sqrt(this.vx * this.vx + this.vy * this.vy);
var maxSpeed = 14;
if (speed > maxSpeed) {
this.vx *= maxSpeed / speed;
this.vy *= maxSpeed / speed;
}
}
}
// do boundary processing if enabled
function particleHandleBoundaries()
{
if (this.bPeriodicBoundaries)
{
if (this.px > width) this.px -= width;
if (this.px < 0) this.px += width;
if (this.py > 280) this.py -= height;
if (this.py < 230) this.py += height;
} else if (this.bHardBoundaries)
{
if (this.px >= width)
{
this.vx = -abs(this.vx);
}
if (this.px <= 0)
{
this.vx = abs(this.vx);
}
if (this.py >= 280)
{
this.vy = -abs(this.vy);
}
if (this.py <= 230)
{
this.vy = abs(this.vy);
}
}
}
// draws particles as circles
function particleDraw()
{
fill(200, 200, 200, 100);
noStroke();
ellipse(this.px, this.py, 18, 18);
}
// add a force to the particle using F = mA
function particleAddForce(fx, fy)
{
var ax = fx / this.mass;
var ay = fy / this.mass;
this.vx += ax;
this.vy += ay;
}
// make a new particle
function makeParticle(x, y, dx, dy)
{
var p = {px: x, py: y, vx: dx, vy: dy,
mass: 1.0, damping: 0.9,
bFixed: false,
bLimitVelocities: true,
bPeriodicBoundaries: false,
bHardBoundaries: true,
addForce: particleAddForce,
update: particleUpdate,
limitVelocities: particleLimitVelocities,
handleBoundaries: particleHandleBoundaries,
draw: particleDraw
}
return p;
}
For this program, I started with the idea of the ruins of human cities. Originally, I wanted to do something with skylines, but in the final project, I instead have three layers of simple buildings moving across the landscape background.
In the midground, I modified the particles program that we went through during class to create an effect that looks like roiling fog.
In the foreground, I drew a large oil rig in various shades of gray to contrast with the bright and colorful background.
As the user clicks the “click me” button, small fires appear on the oil rig. After enough clicks, huge fires appear on the screen, ending with a screen that says BOOM after the oil rig explodes.
I wanted to refrain from using images, so the program has more of a game-like appearance, making a climate apocalypse seem like a “game over”.
]]>//Alana Wu
//ID: alanawu
//Project 11
var planets = [];
var stars = [];
var dots = [];
function setup()
{
createCanvas(400, 400);
for (var i = 0; i < 2; i++) //creates initial planets
{
var pX = random(width);
var pC = [random(50, 255), random(50, 255), random(50, 255)];
var pSize = random (20, 120);
var faceNum = random (1);
var o = random (0,1);
planets[i] = makePlanet(pX, pC, pSize, faceNum, o);
}
for (var i = 0; i < 5; i++) //creates initial dot clusters
{
var aX = random(50, width*2-50);
var aCol = [random(0, 255), random(0, 255), random(0, 255), 75];
var aSize = random (10, 150);
var locationX = [];
var locationY = [];
for (var j = 0; j < 200; j++)
{
var bX = randomGaussian(0, 30);
locationX.push(bX);
var bY = randomGaussian(0, 30);
locationY.push(bY);
}
dots[i] = makeDots (aX, aCol, aSize, locationX, locationY);
}
frameRate(10);
}
function draw()
{
background (0);
updateAndDisplayDots();
removeDots();
addDots();
updateAndDisplayStars();
removeStars();
addStars();
updateAndDisplayPlanets();
removePlanets();
addPlanets();
astronaut();
if (keyIsPressed) //massive sun appears when key is pressed
{
sun();
}
}
function updateAndDisplayPlanets () //moves and draws planets
{
for (var i = 0; i < planets.length; i++)
{
planets[i].move();
planets[i].display();
}
}
function updateAndDisplayStars () //moves and draws stars
{
for (var i = 0; i < stars.length; i++)
{
stars[i].move();
stars[i].display();
}
}
function updateAndDisplayDots () //moves and draws dots
{
for (var i = 0; i < dots.length; i++)
{
dots[i].move();
dots[i].display();
}
}
function removePlanets() //removes planets above the canvas from array
{
var planetsKeep = [];
for (var i = 0; i < planets.length; i++)
{
if (planets[i].y + planets[i].size/2 > 0)
{
planetsKeep.push(planets[i]);
}
}
planets = planetsKeep; //remember surviving planets
}
function removeStars() //removes stars above the canvas from array
{
var starsKeep = [];
for (var i = 0; i < stars.length; i++)
{
starsKeep.push(stars[i]);
}
stars = starsKeep;
}
function removeDots() //removes dots above the canvas from array
{
var dotsKeep = [];
for (var i = 0; i < dots.length; i++)
{
dotsKeep.push(dots[i]);
}
dots = dotsKeep;
}
function addPlanets() //add new planets from bottom
{
var chance = .05;
if (random(1) < chance)
{
planets.push(makePlanet(random(width), [random(50, 255),
random (50, 255), random (50, 255)], random (20, 120), random (1)));
}
}
function addStars() //adds new stars from bottom
{
var chance = .05;
if (random(1) < chance)
{
stars.push(makeStars(random (width)));
}
}
function addDots() //adds new dots from bottom
{
var chance = .5;
if (random(1) < chance)
{
var aX = random(0, width*2-50);
var aCol = [random(0, 255), random(0, 255), random(0, 255), 75];
var aSize = random (10, 150);
var locationX = [];
var locationY = [];
for (var j = 0; j < 200; j++)
{
var bX = randomGaussian(0, 30);
locationX.push(bX);
var bY = randomGaussian(0, 30);
locationY.push(bY);
}
var a = makeDots (aX, aCol, aSize, locationX, locationY);
dots.push(a);
}
}
function makePlanet (planX, c, size, f, o) //makes planet object
{
var planet =
{ x: planX,
y: height,
size: size,
color: c,
speed: -3,
faceNum: f,
move: planetMove,
display: planetDisplay,
orbit: o
}
return planet;
}
function makeStars(sX) //makes star object
{
var star =
{x: sX,
y: height,
speed: -3,
move: starMove,
display: starDisplay
}
return star;
}
function makeDots (aX, col, size, locationX, locationY) //makes dots object
{
var dot =
{x: aX,
y: height*2,
locX: locationX,
locY: locationY,
size: size,
color: col,
speed: -3,
move: dotMove,
display: dotDisplay
}
return dot;
}
function planetMove () //moves planets upwards
{
this.y += this.speed;
}
function starMove () //moves stars upwards
{
this.y += this.speed;
}
function dotMove () //moves dots upwards
{
this.y += this.speed;
}
function planetDisplay () //draws planet
{
fill (this.color);
noStroke();
circle (this.x, this.y, this.size); //colored circle
stroke(0);
strokeWeight(this.size/20);
if (this.faceNum < .33) //dead face, surprised when mouse is pressed
{
line (this.x - this.size/6, this.y - this.size/12, this.x - this.size/6, this.y - this.size/6);
line (this.x + this.size/6, this.y - this.size/12, this.x + this.size/6, this.y - this.size/6);
push();
strokeWeight(this.size/14);
stroke(200);
noFill();
if (this.orbit > .5) //2 possible orbital rings around planet
{
arc (this.x, this.y + this.size/10, this.size*1.4, this.size/3, TWO_PI*.973, PI*1.07); //wide orbital ring
}
else
{
arc (this.x, this.y + this.size/10, this.size*1.1, this.size/6, TWO_PI*.995, PI*1.01); //narrow orbital ring
}
pop();
if (mouseIsPressed) //surprised mouth when mouse is pressed
{
noFill();
ellipse(this.x, this.y, this.size/8, this.size/10);
}
else
{
line (this.x - this.size/12, this.y, this.x + this.size/12, this.y);
}
}
else if (this.faceNum >= .33 & this.faceNum < .66) //eyes on left, smile, frown if mouse is pressed
{
fill (0);
circle (this.x - this.size/3, this.y - this.size/12, this.size/8);
circle (this.x - this.size/6, this.y - this.size/12, this.size/8);
strokeWeight (this.size/20);
noFill();
if (mouseIsPressed) //frowns when mouse is pressed
{
arc (this.x - this.size/4, this.y + this.size/12, this.size/20, this.size/30, PI, 0 , OPEN);
}
else
{
arc (this.x - this.size/4, this.y + this.size/12, this.size/20, this.size/30, 0, PI, OPEN);
}
fill (255);
noStroke();
circle (this.x - this.size/3 - this.size/20, this.y - this.size/12, this.size/18);
circle (this.x - this.size/6 - this.size/20, this.y - this.size/12, this.size/18);
}
else //eyes on right, smile, frowns if mouse is pressed
{
fill (0);
circle (this.x + this.size/3, this.y - this.size/12, this.size/8);
circle (this.x + this.size/6, this.y - this.size/12, this.size/8);
noFill();
if (mouseIsPressed) //frowns when mouse is pressed
{
arc (this.x + this.size/4, this.y + this.size/12, this.size/20, this.size/30, PI, 0, OPEN);
}
else
{
arc (this.x + this.size/4, this.y + this.size/12, this.size/20, this.size/30, 0, PI, OPEN);
}
fill (255);
noStroke();
circle (this.x + this.size/3 - this.size/20, this.y - this.size/12, this.size/18);
circle (this.x + this.size/6 - this.size/20, this.y - this.size/12, this.size/18);
}
}
function starDisplay() //draws stars
{
fill (255, 255, 200);
noStroke();
beginShape();
vertex (this.x + 10, this.y);
vertex (this.x + 3, this.y - 1);
vertex (this.x, this.y - 8);
vertex (this.x - 3, this.y - 1);
vertex (this.x - 10, this.y);
vertex (this.x - 4, this.y + 3);
vertex (this.x - 7, this.y + 10); //bottom left triangle
vertex (this.x, this.y + 5); //middle inner vertex
vertex (this.x + 7, this.y + 10);//bottom right triangle
vertex (this.x + 4, this.y + 3);
vertex (this.x + 10, this.y);
endShape();
}
function dotDisplay() //draws colored dots
//dotDisplay is called EVERY frame, so the randomGaussians change every frame
//get program to push of randomGaussian locations into an array of locaitons when a set of dots is created
//then call those same locations for every frame for that set of dots
{
push();
scale(.5);
stroke(this.color);
for (var i = 0; i < this.locX.length; i++)
{
push();
translate (this.x, this.y);
point(this.locX[i], this.locY[i]);
pop();
}
pop();
}
function astronaut () //draws astronaut hanging from moon balloon
{
//moon balloon
push();
translate (0, -30);
fill (255, 200, 50);
noStroke();
circle (width/2, height/2, 100);
triangle (width/2, height/2 + 30, width/2 - width/43, height/2 + 58, width/2 + width/43, height/2 + 58);
fill (150, 75, 0, 100);
stroke(0);
strokeWeight(3);
arc (width/2 - width/14, height/2 + height/20, 10, 10, PI/6, PI*1.8, OPEN);
arc (width/2, height/2, 20, 20, 0, PI*1.5, OPEN);
arc (width/2 + width/20, height/2 - height/17, 25, 25, PI/2, TWO_PI, OPEN);
arc (width/2 - width/15, height/2 - height/18, 15, 15, PI*2.7, PI*1.7, OPEN);
arc (width/2 - width/30, height/2 + height/12, 12, 12, TWO_PI, PI*7/8, OPEN);
arc (width/2 + width/16, height/2 + height/18, 22, 22, PI*1.7, PI, OPEN);
stroke(255);
line (width/2, height/2 + 58, width/2, height/2 + 82);
push();
translate (width*.59, height*.68);
fill(255);
push(); //balloon arm
rotate (radians(-40));
ellipse (-30, 5, 15, 50);
rotate(radians(48));
ellipse (24, 30, 15, 25); //non balloon arm
pop();
ellipse(-5, 35, 45, 55); //body
ellipse (-14, 60, 15, 35); //left leg
ellipse (6, 60, 15, 35); //right leg
push(); //helmet
rotate (radians(25));
fill (255);
ellipse (-25, 0, 10, 20);
ellipse (25, 0, 10, 20);
ellipse (0, 0, 50, 45);
fill (0, 0, 100); //navy part
ellipse (0, 0, 50, 35);
noStroke();
fill (255, 255, 255);
ellipse (14, -2, 8, 12); //large white bubble
rotate (radians(-10));
ellipse (-17, 3, 3, 5); //smaller white bubble
strokeWeight(8); //belt
stroke(220);
line (-13, 45, 24, 39);
strokeWeight(2);
stroke(0);
fill(220);
rotate(radians(-10));
rect (-11, 37, 20, 10);
pop();
pop();
pop();
}
function sun () //massive sun appears when key is pressed
{
noStroke();
fill (255, 255, 0);
circle (width/2, height/2, 300);
strokeWeight(10);
stroke(255, 255, 0);
push();
translate (width/2, height/2);
for (var i = 0; i < 36; i ++)
{
line (0, -170, 0, -230);
rotate (radians (30));
}
pop();
}
For this project, I decided to depict an astronaut floating through space. The elements I have passing by are various types of planets, individual stars, and faraway colorful clusters of stars. This project prompt let me play around with lots of fun colors and shapes, while also helping me learn how objects work. I started with the planets object, and ended with the colorful clusters of dots. I also added features where the facial expressions of the planets change when you press the mouse and a sun appears if you press a key.
The article “Art Project Shows Racial Biases in Artificial Intelligence System” spoke about ImageNet Roulette, which is an artificial intelligence tool that classifies images of people with different tags, such as politician, doctor, father, newsreader, etc. The tool was created by Trevor Pagan and Kate Crawford specifically to reveal “how layers of bias and racism and misogyny move from one system to the next.” (Pagan) The creators were using this project to reveal how ImageNet, which is use to train many artificial intelligence systems, inherently has racist biases.
The structure of this project was quite effective, as it revealed how so many of the systems we use have biases built into them, which often leads to significantly detrimental effects. Reading the article makes me wonder about to what extent the other systems we use have racial bias built into them – infrastructure, social media, architecture, etc. However, it’d be harder to reveal the inherent biases in physical systems like infrastructure, since there isn’t a pool of data you can pull from like in the case of artificial intelligence learning systems. Regardless, it’s important that we reveal the racial biases that are entrenched in our society. We can’t build future systems that are equal without changing our current ones.
]]>This project depicts a bicycle moving along a path through different scenery. Different sound effects play as the bicycle passes through grass, birds fly by, trees and fall foliage appear, and night starts to fall.
//Alana Wu
//ID: alanawu
//Project 10: Sonic Story
var birdSound;
var autumn;
var chimes;
function preload()
{
chimes = loadSound("http://localhost:8000/chimes3.wav");
birdSound = loadSound("http://localhost:8000/bird.wav");
autumn = loadSound("http://localhost:8000/autumn.wav");
chirping = loadSound("http://localhost:8000/chirping.wav");
}
function setup()
{
createCanvas(400, 400);
useSound();
frameRate(5);
}
function soundSetup()
{
birdSound.setVolume(5);
autumn.setVolume(3);
autumn.amp (.4);
chimes.setVolume(.5);
}
var x;
var y;
function draw()
{
background(0, 200, 255);
//biking through the grass, windchimes playing
if (frameCount < 40)
{
grass();
chimes.play();
}
//birds fly by and chirp
if (frameCount >= 40 & frameCount < 80)
{
bird(width + 400 - frameCount*10, frameCount*4);
bird(width + 430 - frameCount*10, height - frameCount*5);
bird(width + 400 - frameCount*10, height/2 - frameCount*3);
bird(width + 420 - frameCount*10, height/3 + frameCount*2);
bird(width + 400 - frameCount*10, 15 + frameCount*2);
if (frameCount % 8 == 0)
{
birdSound.play();
}
}
//bike through the autumn trees, wind is blowing
if (frameCount >= 80 & frameCount < 160)
{
if (frameCount % 10 == 0 && frameCount < 120)
{
autumn.play();
}
background(0, 200, 255);
trees (width + 1120 - frameCount*14, height);
}
if (frameCount >= 140)
{
night();
}
noStroke();
fill (200);
//road and bicycle
rect (0, 385, width, 20);
bicycle(150, 350);
//ends program after a certain amount of time
if (frameCount > 200)
{
noLoop();
}
}
function bicycle (x, y)
{
stroke(0);
strokeWeight(5);
noFill();
circle (x, y, 70, 70);
circle (x + 100, y, 70, 70);
line (x, y, x + 50, y);
line (x + 50, y, x + 32, y - 42);
line (x + 24, y - 42, x + 42, y - 42);
line (x + 50, y, x + 90, y - 55);
line (x + 88, y - 65, x + 100, y);
line (x + 88, y - 65, x + 72, y - 65);
}
function bird (x, y)
{
noStroke();
fill (0, 0, 255);
ellipse (x, y, 40, 32);
push();
translate(x, y);
rotate (radians(5));
ellipse(20, 5, 10, 5);
rotate (radians(15));
ellipse(20, 4, 10, 5);
//wing
fill (170, 220, 255);
ellipse(6, 4, 11, 6);
rotate(radians(-25));
ellipse(5, 3, 11, 6);
rotate(radians(-25));
ellipse(4, 2, 11, 6);
pop();
fill (255);
ellipse (x - 8, y - 5, 12, 12);
fill (0);
ellipse (x - 10, y - 5.5, 6, 6);
fill (255, 180, 30);
triangle (x - 26, y + 8, x - 19, y, x - 15, y + 9);
}
function grass()
{
fill (0, 230, 0);
noStroke();
push();
translate (400 - frameCount*20, 0);
for (var x = width; x >= 0; x -= 20)
{
triangle (x, height, x + 20, height, x + 10, height - 100);
}
pop();
}
function trees (x)
{
//green tree
noStroke();
fill (100, 50, 0);
triangle (x - 10, height, x + 10, height, x, height - 100);
triangle (x - 26, height - 55, x, height - 55, x, height - 45);
triangle (x + 35, height - 60, x, height - 65, x, height - 55);
fill (0, 150, 0);
circle (x - 25, height - 100, 60);
circle (x + 25, height - 120, 75);
circle (x + 35, height - 60, 50);
circle (x - 30, height - 55, 40);
//yellow tree
x += 75;
fill (100, 50, 0);
triangle (x - 10, height, x + 10, height, x, height - 250);
fill (255, 200, 0);
ellipse (x, height - 250, 80, 110);
//red orange yellow tree
x += 200;
fill (100, 50, 0);
triangle (x - 10, height, x + 15, height, x, height - 200);
fill (255, 130, 0);
circle (x + 15, height - 135, 50);
fill (255, 50, 50);
circle (x, height - 170, 80);
fill (240, 230, 0);
circle (x - 18, height - 125, 40);
//tallest tree
x -= 75;
fill (100, 50, 0);
triangle (x + 20, height, x-10, height, x + 5, 0);
fill (255, 255, 0);
circle (x + 20, 90, 50);
fill (200, 255, 0);
circle (x + 25, 5, 100);
fill (150, 255, 0);
circle (x + 10, 45, 70);
fill (100, 255, 0);
circle (x-12, 70, 60);
}
//sky becomes night time, stars come out
function night()
{
if (frameCount % 15 == 0)
{
chirping.play();
}
background (0, 200 - (frameCount - 140), 255 - (frameCount-140));
fill (255);
noStroke();
if (frameCount > 160)
{
circle (random(width),random(height), 10);
}
circle (random(width),random(height), 10);
circle (random(width),random(height), 10);
}
]]>I started off by playing with different shapes and ways to depict the image. Here are some of the variations I tried.
The variation I chose drew the image with randomly bouncing particles. When pressing a key, the color of the particles would be rainbow. When pressing the mouse, larger, black particles moved around the page to act as “erasers”.
//Alana Wu
//ID: alanawu
//Project 09
var img;
var balls = [];
var ballNum = 15;
function preload()
{
img = loadImage ("https://i.imgur.com/2U02mf4.jpg");
}
function makeBall (ax, ay, adx, ady)
{
var a = {
x: ax,
y: ay,
dx: adx,
dy: ady,
dirX: 1,
dirY: -1,
stepFunction: moveBall,
drawFunction: drawBall
}
return a;
}
function moveBall ()
{
//bounce off of walls
if (this.x >= 338 || this.x <= 0)
{
this.dirX *= -1;
}
if (this.y >= 400 || this.y <=0)
{
this.dirY *= -1;
}
this.x += this.dx*this.dirX + random(-3, 3);
this.y += this.dy*this.dirY + random(-3, 3);
}
function drawBall ()
{
//color of ball = pixel from image in that location
var col = img.get(this.x, this.y);
fill (col);
//when key is pressed, taste the rainbow :)
if (keyIsPressed)
{
fill (random(255), random(255), random(255));
}
//draws balls
circle (this.x, this.y, 5, 5);
//when mouse is pressed, black jittery particles that act as erasers
if (mouseIsPressed)
{
fill (0);
circle (this.x + random(40), this.y + random(40), 20);
}
}
function setup()
{
createCanvas(338, 400);
background(0);
noStroke();
//fits image to canvas size
img.resize(width, height);
//makes objects for each ball
for (var i = 0; i < ballNum; i++)
{
a = makeBall (0,0, random(5), random(5));
balls.push(a);
}
}
function draw()
{
for (var i = 0; i < balls.length; i++)
{
balls[i].drawFunction();
balls[i].stepFunction();
}
}
//other shapes and ideas I played with, but didn't use
function ripple2 (size)
{
for (var x = 0; x < size; x+=5)
{
for (var y = 0; y < size; y+=5)
{
fill (0);
circle (mouseX + x + 8, mouseY + y + 8, 5);
circle(mouseX - x + 8, mouseY - y + 8, 5);
}
}
for (var x = 0; x < size; x+=5)
{
for (var y = 0; y < size; y+=5)
{
var col = img.get(mouseX + x,mouseY +y);
fill(col);
circle (mouseX + x, mouseY + y, 5);
var col2 = img.get(mouseX - x, mouseY - y);
fill (col2);
circle(mouseX - x, mouseY - y, 5);
}
}
}
function shape1 (x, y, dx, dy) //diagonal lines
{
for (var y = 0; y < height; y += dy)
{
for (var x = 0; x < width; x += dx)
{
var col = img.get(x, y);
strokeWeight (mouseX/100);
stroke (col);
line (x, y, x + dx, y + dy);
}
}
}
function shape2 (x, y, size) //circles, animated if w/ random
{
for (var y = 0; y < height; y += size)
{
for (var x = 0; x < width; x += size)
{
var col = img.get(x, y);
fill(col);
circle (x, y, size);
}
}
}
function shape3 (x, y, w, h) //moving ellipse in a ripple effect
{
for (var y = 0; y < height; y += h)
{
for (var x = 0; x < width; x += 15)
{
var col = img.get(x, y);
fill(col);
ellipse (x, y, random(35), h);
}
}
}
function shape4 (x, y, size) //triangles that slowly get bigger along the diagonal
{
for (var y = 0; y < height; y += size/3)
{
for (var x = 0; x < width; x += size)
{
var col = img.get(x, y);
fill(col);
triangle (x, y, x + size, y + size, x - size, y + size);
}
size += size/10;
}
}
function ripple ()
{
var x = 0;
var y = 0;
var r = 5;
push();
for (var j = 0; j < count; j++)
{
for (var i = 0; i < count; i++)
{
x = r*cos(radians(i*200));
y = r*sin(radians(i*200));
var col = img.get(mouseX + x, mouseY + y);
fill (col);
circle (mouseX + x, mouseY + y, 5, 5);
}
r += 5;
}
pop();
}
function drawIt () //uncovers image w/ mouse location
{
var col = img.get(mouseX, mouseY);
fill (col);
circle (mouseX, mouseY, 15, 15);
}
]]>A permanent art installation created in 2012, Assembly is built of acrylic blocks and steel combined with digital emulsion. 5,500 blocks hang in the air, while digital light is projected onto their faces. This allows the spectator to study “a boundary line between digital and natural worlds, experiencing figurations of imaginary digital forms rendered into the limiting error-driven physical system.” The artist is trying to display how for the digital world to exit in the real world, it must bend to the rules of physical existence, while also gaining new possibilities.
Assembly was produced by Kimchi and Chips, a Seoul based art studio founded by Mimi Son and Elliot Woods in 2009. They use a research based approach, especially with volumetric images in fog and 3D projection onto non-design forms.
For Assembly, the production staff are Minjae Kim and Minjae Park. The mathematicians are Daniel Tang and Chris Coleman-Smith.
What drew me to this project is how it combines such rigid, physical objects with something as malleable and inconstant as digital light. Until recently, artwork has been restricted to one medium, or groups of similar media. With recent development of so much digital technology, artists have countless more options. Technology is also at the point where combining vastly different mediums is relatively accessible for the average artist, which will allow art to constantly evolve and expand in its possibilities.
]]>Eyeo 2019 – Refik Anadol from Eyeo Festival on Vimeo.
Refik Anadol is a director and media artist, who works with site-specific public art that uses a parametric data sculpture approach, and live audio and visual performances that use immersive installations. He was born in Istanbul, Turkey, and currently lives and works in LA, California.
He describes himself as being intrigued by how the transformation of subjects in contemporary culture requires rethinking how we perceive space from an aesthetic, technical, and dynamic viewpoint. He also explores embedding media arts into architecture and encourages viewers to visualize alternative realities by presenting the possibility of redefining the functionality of architectural spaces. Anadol suggests that all spaces and facade have the potential to be a canvas for a media artist.
His body of work includes a lot of immersive indoor art installations and outdoor/public art installations, most of which use visual media based upon algorithms and data. I admire how he views the facades and spaces of architecture as potential for media artwork. Public art has a lot of potential to change a community for the better, while also exposing children in lower income communities to possibilities like art.
I liked that he explained his own journey in terms of unique mentors and experiences that had helped him along the way. It helps explain how he got to where he is, while also exposing the audiences to many other helpful resources. Presentation wise, he utilized humor, quotes, and compliments (to his mentors) in such a way that his presentation was very dynamic.
]]>//Alana Wu
//ID: alanawu
//Project 07 Mathematical Curves
var nPoints1 = 40;
var nPoints2 = 550;
var nPoints3 = 100;
var whichCurve = 1;
function setup()
{
createCanvas(480, 480);
background(0);
stroke (255);
}
function draw()
{
translate (width/2, height/2);
if (whichCurve == 0)
{
rotate (radians (constrain (mouseY, 50, height - 50)));
sinusoidSpiral ();
}
if (whichCurve == 1)
{
rotate (radians (mouseX));
archiSpiral();
}
if (whichCurve == 2)
{
astroidCurve();
}
}
//https://mathworld.wolfram.com/SinusoidalSpiral.html
function sinusoidSpiral () //r^n = (a^n)cos(n*theta)
{
var x;
var y;
var a = mouseX/10;
var b = constrain (mouseX/10, 2, 9);
var theta = radians (0);
fill (mouseX - 100, mouseY - 100, mouseY - 100);
beginShape();
for (var i = 0; i < nPoints1; i++)
{
var theta = map(i, 0, nPoints1, 0, TWO_PI);
x = a * (b*cos(theta) - cos(b * theta));
y = a * (b * sin(theta) - sin(b * theta));
vertex (x, y);
}
endShape(CLOSE);
}
//https://mathworld.wolfram.com/ArchimedeanSpiral.html
function archiSpiral ()
{
var x;
var y;
var a = mouseX/10;
var n = 10;
push();
background(0);
noFill();
stroke(255);
strokeWeight(.2);
beginShape();
for (var i = 0; i < nPoints2; i++)
{
var theta = map (i, 0, nPoints2, 0, TWO_PI*2);
x = a * cos (theta) * (theta)^(1/n); //x = rcos(theta)
y = a * sin(theta)*theta^(1/n) + random(-5, 5); //x = rsin(theta)
stroke (mouseX, 0, mouseY);
vertex (x, y);
}
endShape(CLOSE);
pop();
}
//https://mathworld.wolfram.com/AstroidRadialCurve.html
function astroidCurve ()
{
var x;
var y;
var a = 200;
push();
background(0);
stroke(mouseX, mouseX/10, mouseY + 30);
noFill();
beginShape();
for (var i = 0; i < nPoints3; i++)
{
var theta = map (i, 0, nPoints3, 0, TWO_PI);
x = a * (cos (theta))^3 + random (-5, 5);
y = a * (sin(theta))^3 + random (-5, 5);
print (x);
print (y);
vertex (x, y);
}
endShape(CLOSE);
pop();
}
//which shape is drawn changes when mouse is clicked
function mousePressed ()
{
whichCurve++;
if (whichCurve == 3)
{
whichCurve = 0;
}
}
For this project, I chose to use a sinusoidal spiral, an archimedes spiral, and an astroid radial curve. I spent a lot of time altering the parameters to see how they affected the shapes. To add user interaction, I had different aspects of the shapes change with the mouse location, while which curve drawn changed as the mouse was clicked. I particularly liked playing with the colors and rotations of sinusoidal spiral.
Doing this project also made me wonder how other mathematical concepts can be visualized, and whether or not that could help people understand certain mathematical concepts better.
Creator: Chris Harrison
Link: https://www.chrisharrison.net/index.php/Visualizations/InternetMap
This map visualizes the city-to-city Internet connections, which play a huge role in our lives nowadays. For those of us in the US, it seems like we would no longer be able to survive without the Internet. Yet looking at this map helped me realize how millions of people have little to no access to the Internet. Being connected online feels like a guarantee for many of us, and at least for me, this map made me realize that I’ve been taking granted how easy it is to access the Internet, when in reality, access to the Internet would be a life changing resource for the millions of people without access.
This project also made me wonder about the quantity of communication between high internet usage countries and low internet usage countries. Due to globalization, the choices that more powerful countries make can drastically affect every single other country in the world. It seems to me that as a resource, the Internet has become so fundamental for so many things that lack of Internet access and infrastructure is a huge disadvantage for many countries and people.
The map was created with data from the DIIMES Project. It displays a total of 89,344 connections.
//Alana Wu
//ID: alanawu
//Project 06 Abstract Clock
function setup()
{
createCanvas(400, 400);
}
function draw()
{
//color of background changes by minute
fill (minute()*5, minute()*3 + 100, 255 - minute());
rect (0, 0, 400, 400);
//how many curves are drawn depends on hour
if (hour() > 0)
{
anenome (100, 240, 240, 10, 65);
}
if (hour() > 1)
{
anenome (200, 255, 230, 35, 53)
}
if (hour() > 2)
{
anenome (200, 0, 200, 17, 35);
}
if (hour() > 3)
{
anenome (255, 200, 230, 25, 5);
}
if (hour() > 4)
{
anenome (255, 100, 170, 30, 75);
}
if (hour() > 5)
{
anenome (100, 240, 240, 10, 65);
}
if (hour() > 6)
{
anenome (255, 255, 200, 15, 25);
}
if (hour() > 7)
{
anenome (200, 220, 50, 25, 40);
}
if (hour() > 8)
{
anenome (150, 100, 255, 10, 85);
}
if (hour() > 9)
{
anenome (0, 200, 255, 24, 30);
}
if (hour() > 10)
{
anenome (200, 180, 255, 8, 30);
}
if (hour() > 11)
{
anenome (255, 50, 50, 28, 92);
}
//draws 3 octopi, each of which display, hour, minute, or second
octopus(mouseX, mouseY - 25, minute());
octopus(mouseX + 30, mouseY + 25, second());
octopus(mouseX - 30, mouseY + 25, hour());
//while within the canvas, waves move down each second
waveRows(constrain (second()*25 + 50, 0, height+20));
}
//grid of waves
function waveRows (start)
{
red = 10;
green = 100;
blue = 255;
for (var h = start; h < height + 60; h +=50)
{
row3(h);
row4(h);
}
}
//horizontal row of 3 waves
function row3 (y)
{
for (var x = 85; x <= width; x += 125)
{
for (var i = 5; i > 0; i--)
{
strokeWeight (1);
fill (red, green, blue);
ellipse (x, y - 25, i*20, i*20);
red += 30;
green += 30;
}
red = 10;
green = 100;
}
}
//horizontal row of 4 waves
function row4 (y)
{
for (var x = 25; x <= width; x += 125)
{
for (var i = 5; i > 0; i--)
{
strokeWeight (1);
fill (red, green, blue);
ellipse (x, y, i*20, i*20);
red += 30;
green += 30;
}
red = 10;
green = 100;
}
}
//draws colorful wavy curve
function anenome (red, green, blue, length, tilt)
{
push();
translate (10, 350);
frameRate (6);
rotate (radians (-tilt));
for (var n = 0; n < 10; n++)
{
for (var x = 0; x < length; x += .1)
{
noStroke();
fill (red, green, blue);
circle (x*20 + random (0,15), -25*cos(x) + random (0, 15), 13-x);
}
}
pop ();
}
//draws octopus w/ a color that changes by the minute
function octopus (x, y, time)
{
noStroke();
fill (minute()*10, 255 - minute(), 250);
ellipse (x, y, 50, 40);
for (var i = 0; i < 5; i++)
{
push();
translate (x, y);
rotate (radians (i*15 - 29));
ellipse (15 - i*6.8, 22, 10, 20);
pop();
}
fill (0);
ellipse (x - 12, y + 2, 8, 8);
ellipse (x + 12, y + 2, 8, 8);
noFill();
stroke(0);
arc (x, y+7, 8, 8, 0, PI, OPEN);
strokeWeight (1);
textSize (10);
text (time, x - 14, y - 6);
}
In this project, the abstract waves change by second, the three octopi reflect the time, the number of colorful curves (I was originally thinking anemone, but it really didn’t translate and I liked these anyways) change by the hour, and the colors of the background and the octopi change as the time changes.
]]>