Final Project

sketch

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

Project 11: Landscape

sketch

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

Looking Outwards 10: Biases

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.

Project 10

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.

sketch

//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);
}






Project 09: Portrait

I started off by playing with different shapes and ways to depict the image. Here are some of the variations I tried.

cross hatching
large circles
star shapes made of circles, controlled by mouse location
squares made of circles, with black shadows

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

random colors when key is pressed

sketch

//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);
}

Looking Outwards 09: A Focus on Women and Non-binary Practitioners in Computational Art

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.

LO 08:

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.

Project 07: Mathematical Curves

sketch

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

Looking Outwards: Information Visualization

World City-to-City connections

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. 

World Connection Density

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.

European City-to-City Connections

Project 06: Abstract Clock

sketch

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