Final Project

For my final project, I wanted to show that climate change is not just a singular concept, but rather a buildup of many different factors and situations, as well as how they are related to one another. First, trees are cut down to clear space for more buildings, people in these buildings require electricity which requires the burning of fossil fuels, and the release of carbon dioxide into the air exacerbates global warming and melts glaciers that increase ocean levels.

The user goes through these 3 scenes and interacts with them, worsening the situation. At the end of each scene, they are presented with statistics of each action and they realize those consequences. Perhaps the polar bear is a metaphor for humans and at the end when the polar bear “drowns”, the user is asked “Are you sorry now?” telling them to rethink their actions before it is too late.

If I had more time, I would have liked to make my graphics more detailed. I would have also liked to include sound but I was having too many problems with looping the sounds so I decided not to include them.

sketch

//Catherine Liu
//jianingl@andrew.cmu.edu
//Section D
//Final Project

//An interactive narrative consisting of 3 scenes

var scene = 1;
var frameNum = 0;

var trees = []; //array to hold objects for trees
var treeCount = 0; //keeping track of framecount specifically for trees
var buildings = []; //array to hold objects for buildings

var lightSwitch = false; //tracking if switch is on or off
var smokeTrail1 = []; //array for holding smoke trail
var smokeTrail2 = []; //array for holding smoke trail

var seaHeight; //tracking height of sea
var gameFail = 0; //tracking if polar bear has drowned
var finalFrame = false; //tracking framecount to show final frame
var finalCount = 0; //tracks count of final frame

//making sine wave for ocean (code refrenced from p5js.org)
var xspacing = 5; // Distance between each horizontal location
var w; // Width of entire wave
var theta = 0.0; // Start angle at 0
var amplitude = 25.0; // Height of wave
var period = 500.0; // How many pixels before the wave repeats
var dx; // Value for incrementing x
var yvalues; // Using an array to store height values for the wave

function setup() {
    createCanvas(600,400);

    //adds trees to array
    for (i = 0; i < 5; i++) {
        var rx = random(width);
        trees[i] = makeTree(rx);
    }

    // create an initial collection of buildings
    for (var i = 0; i < 10; i++){
        var rx = random(width);
        buildings[i] = makeBuilding(rx);
    }

    //sets up smoke object
    for (i = 170; i > 50 ; i-=15) {
        smoke1 = { x: 400 + random(-10,10),
                  y: i,
                  size: random(30,50)
                }
        smokeTrail1.push(smoke1)

        smoke2 = {x: 500 + random(-10,10),
                  y: i,
                  size: random(30,50)
                }
        smokeTrail2.push(smoke2)
    }

    //setting up sine wave 
    w = width + 16;
    dx = (TWO_PI / period) * xspacing;
    yvalues = new Array(floor(w / xspacing));
}

function draw() {

    //tracking framecount for scenes to show up
    frameNum += 1

    if (frameNum == 200){
        scene = 1.5
    }

    if (frameNum == 250){
        scene = 2;
    }

    if (frameNum == 450){
        scene = 2.5
    }

    if (frameNum == 500) {
        scene = 3;
    }

    if (finalFrame) {
        finalCount += 1;
    }

    //Scene 1: Cutting down trees
    if (scene == 1) {
        background(230,230,250);
        noStroke();
        fill(0,100,0);
        rect(0,height-50,width,50)

        //show trees until a certain point and switch to buildings
        if (treeCount <= 120) {
            textSize(20);
            textAlign(CENTER);
            text("Try cutting down trees with the saw", width/2, 30);
            updateAndDisplayTrees();
            removeTrees();
            addNewTree();
            treeCount += 1
        }
        if (treeCount > 120) {
            fill(50);
            rect(0,height-50,width,50)
            text("There's no more trees to cut...", width/2, 30);
            updateAndDisplayBuildings();
            removeBuildings();
            addNewBuildings(); 
        }

        //function for making saw
        drawSaw(); 
    }

    if (scene == 1.5) {
        background(0);
        textSize(20);
        textAlign(CENTER);
        fill(255);
        text("More than 3.5 billion trees are cut down annually",width/2,height/2);
        text("for human needs and urban development", width/2, height/2+30)
    }

    //Scene 2: Factory producing smoke
    if (scene == 2) {
        //function for creating smoke
        factorySmoke();

        fill(255)
        text("Click the light switch...", 120,90);
        text("watch the window",120,120);
    }

    if (scene == 2.5) {
        background(0);
        textSize(20);
        textAlign(CENTER);
        fill(255);
        text("62% of our electricity comes from fossil fuels",width/2,height/2);
        text("1.5 million metric tons of C02 are released annually",width/2,height/2+30)
    }

    //Scene 3: rising ocean levels and melting glaciers
    if (scene == 3) {
        noStroke();
        frameRate(10);
        background(70,130,180);
        textSize(20);
        textAlign(CENTER);
        fill(255);
        text("Keep the polar bear above the water, or else...",width/2,30)

        //drawing mountains
        fill(100,146,198);
        triangle(0,height,150,50,300,height);
        triangle(450,height,550,100,650,height);
        fill(135,206,235);
        triangle(100,height,300,150,500,height);

        //draw polar bear that follows mouse
        polarBear();

        //drawing wave
        seaHeight = map(frameNum,500,700,height,-10);
        fill(193,223,255);
        calcWave();
        renderWave(seaHeight);
        
        // if polar bear drowns too many times or ocean rises canvas top, scene ends
        if (gameFail>=10 || seaHeight <= 0) {
            background(0);
            fill(255);
            text("The ocean is expected to rise 15-25cm by 2050",width/2,height/2);
            finalFrame = true;
        }
    }

    if (finalCount>20) {
        background(0);
        text("Are you sorry now?", width/2, height/2);
    }
}

function treeDisplay() {
    //draw each tree
    //checking for saw intersection with tree
    treeUpdate();

    frameRate(10);
    
    //tree spawns initially but if saw intersects with tree, only draw trunk
    if (this.intersect == false) {
        noStroke();
        fill(194, 178, 128);
        push();
        translate(this.x,height-40);
        rect(0,-this.vert,this.hor,this.vert);
        fill(0,this.color,100);
        ellipse(this.hor,-this.vert,this.crown1,this.crown2);
        pop();
    } else if (this.intersect == true) {
        fill(101,67,33);
        push();
        translate(this.x,height-40);
        rect(0,-this.vert/2,this.hor,this.vert/2);
        pop();
    }
}

function treeMove() {
    this.x += this.speed;
}

function makeTree(treeX) {
    var tree= {x:treeX,
                hor: random(10,20),
                vert: random(150,250),
                speed: -3,
                color: random(255),
                crown1: random(80,100),
                crown2: random(50,80),
                intersect: false,
                move: treeMove,
                display: treeDisplay,
                update: treeUpdate,
            }
    return tree
}

function updateAndDisplayTrees() {
    for (var i = 0; i < trees.length; i++){
    trees[i].update();
    trees[i].display();
    trees[i].move();
    }
}

function removeTrees() {
    //if tree goes off canvas, remove it
    var treesToKeep = [];
    for (var i = 0; i < trees.length; i++){
        if (trees[i].x + trees[i].crown2 > 0) {
            treesToKeep.push(trees[i]);
        }
    }
    trees = treesToKeep; 
}

function addNewTree() {
    //add new trees after trees move off canvas
    var newTreeLikelihood = 0.06; 
    if (random(0,1) < newTreeLikelihood) {
        trees.push(makeTree(width));
    }
}

function drawSaw() {
    fill(100);
    rect(mouseX, mouseY,80,20);
    for (i = mouseX+5; i < mouseX + 85; i += 10) {
         circle(i, mouseY+20, 10);
    }
    fill("red")
    rect(mouseX-30,mouseY,40,20,20);

}

function updateAndDisplayBuildings(){
    // Update the building's positions, and display them.
    for (var i = 0; i < buildings.length; i++){
        buildings[i].move();
        buildings[i].display();
    }
}

function removeBuildings(){
    //remove buildings as they go off screen
    var buildingsToKeep = [];
    for (var i = 0; i < buildings.length; i++){
        if (buildings[i].x + buildings[i].breadth > 0) {
            buildingsToKeep.push(buildings[i]);
        }
    }
    buildings = buildingsToKeep; // remember the surviving buildings
}

function addNewBuildings() {
    // With a very tiny probability, add a new building to the end.
    var newBuildingLikelihood = 0.007; 
    if (random(0,1) < newBuildingLikelihood) {
        buildings.push(makeBuilding(width));
    }
}

function buildingMove() {
    this.x += this.speed;
}

function buildingDisplay() {
    // draw the building and some windows
    var floorHeight = 40;
    var bHeight = this.nFloors * floorHeight; 
    fill(this.wallCol); 
    noStroke() 
    push();
    translate(this.x, height - 40);
    rect(0, -bHeight, this.breadth, bHeight);
    fill(this.windowCol); 
    for (var i = 0; i < this.nFloors; i++) {
        rect(5, -15 - (i * floorHeight), this.breadth - 10, 10);
    }
    pop();
}

function makeBuilding(birthLocationX) {
    var bldg = {x: birthLocationX,
                breadth: 50,
                speed: -3,
                nFloors: round(random(2,8)),
                windowCol: random(200,255),
                wallCol: random(100,150),
                move: buildingMove,
                display: buildingDisplay}
    return bldg;
}

function factorySmoke() {

    //tracking height of smoke so it moves down every frame
    var smokeLevel = map(frameNum,250,450,0,150); 

    if (lightSwitch == false) { //if light is off
        frameRate(20);
        noStroke();
        background(176,196,222);

        fill(100);
        //moving smoke up the canvas by adding random dx and dy
        for (i = 0; i < smokeTrail1.length; i++) {
            var randomDx = (random(5));
            var randomDy = (random(-5,0));
            smokeTrail1[i].x += randomDx;
            smokeTrail1[i].y += randomDy;
            //reset x and y position if smoke leaves canvas
            if (smokeTrail1[i].y <= 10) {
                smokeTrail1[i].x = 400 + random(-10,10);
                smokeTrail1[i].y = 150;
            }
            circle(smokeTrail1[i].x, smokeTrail1[i].y, 50)
        }

        for (i = 0; i < smokeTrail2.length; i++) {
            var randomDx = (random(5));
            var randomDy = (random(-5,0));
            smokeTrail2[i].x += randomDx;
            smokeTrail2[i].y += randomDy;
            //reset x and y position if smoke leaves canvas
            if (smokeTrail2[i].y <= 10) {
                smokeTrail2[i].x = 500 + random(-10,10);
                smokeTrail2[i].y = 200;
            }
            circle(smokeTrail2[i].x, smokeTrail2[i].y, 50)
        }

        //smoke funnels
        fill(10);
        rect(370,160,50,150);
        rect(470,210,50,120);

        //drawing smoke accumulating at top of window
        calcWave();
        fill(100);
        beginShape();
        vertex(width,0);
        vertex(0,0);
        for (let x = 0; x <= yvalues.length; x++) {
            vertex(x * xspacing,  smokeLevel+ yvalues[x])
        }
        endShape(CLOSE);

        //walls
        fill(178,157,105);
        rect(0,0,width,30);
        rect(0,0,width-370,height);
        rect(0,width,-10,height);
        rect(0,height,width,-(height-310));

        //light switch
        fill(255);
        rect(70,140,70,100);
        fill(210);
        rect(75,190,60,45);

    }else if (lightSwitch == true) { //if light is turned on
        frameRate(20);
        noStroke();
        background(176,196,222);

        fill(50);
        //moving smoke up the canvas by adding random dx and dy
        for (i = 0; i < smokeTrail1.length; i++) {
            var randomDx = (random(5));
            var randomDy = (random(-5,0));
            smokeTrail1[i].x += randomDx;
            smokeTrail1[i].y += randomDy;
            //reset x and y position if smoke leaves canvas
            if (smokeTrail1[i].y <= 10) {
                smokeTrail1[i].x = 400 + random(-10,10);
                smokeTrail1[i].y = 150;
            }
            circle(smokeTrail1[i].x, smokeTrail1[i].y, 100)
        }

        for (i = 0; i < smokeTrail2.length; i++) {
            var randomDx = (random(5));
            var randomDy = (random(-5,0));
            smokeTrail2[i].x += randomDx;
            smokeTrail2[i].y += randomDy;
            //reset x and y position if smoke leaves canvas
            if (smokeTrail2[i].y <= 10) {
                smokeTrail2[i].x = 500 + random(-10,10);
                smokeTrail2[i].y = 200;
            }
            circle(smokeTrail2[i].x, smokeTrail2[i].y, 100)
        }

        //smoke funnels
        fill(10);
        rect(370,160,50,150);
        rect(470,210,50,120);

        //drawing smoke accumulating at top of window
        calcWave();
        fill(50);
        beginShape();
        vertex(width,0);
        vertex(0,0);
        for (let x = 0; x <= yvalues.length; x++) {
            vertex(x * xspacing,  smokeLevel+ yvalues[x])
        }
        endShape(CLOSE);

        //walls
        fill(247,224,169);
        rect(0,0,width,30);
        rect(0,0,width-370,height);
        rect(0,width,-10,height);
        rect(0,height,width,-(height-310));

        //lightswitch
        fill(255);
        rect(70,140,70,100);
        fill(210);
        rect(75,145,60,45);
    }
}

function treeUpdate() {
    //if saw intersects with tree, change the state of variable to true
    if (mouseX+40 > this.x & mouseX+40< this.x + this.hor) {
       this.intersect = true;
    }
}

function mousePressed() {
    //turn light switch on and off if mouse is pressed on lightswitch
    if (mouseX>70 & mouseX<140 && mouseY>190 && mouseY<240) {
        lightSwitch = true;
        skySmoke = 1;
    } else if (mouseX>70 & mouseX<140 && mouseY>140 && mouseY<190) {
        lightSwitch = false;
        skySmoke = 0;
    }
}

function polarBear() {
    //draws polar bear
    fill(255);
    ellipse(mouseX,mouseY,100,70);
    circle(mouseX-50,mouseY-30,50);
    circle(mouseX-70,mouseY-50,20);
    circle(mouseX-35,mouseY-50,20);
    rect(mouseX-40,mouseY+20,10,20,10);
    rect(mouseX+30,mouseY+20,10,20,10);
    fill(70,130,180);
    circle(mouseX-60,mouseY-30,5);
    circle(mouseX-40,mouseY-32,5);
    ellipse(mouseX-50,mouseY-25,10,5)

    //if polar bear moves below ocean surface, increase count of fails
    if (mouseY-70 >= seaHeight) {
        gameFail +=1;
    }
}

function calcWave() {
  // Increment theta (try different values for
  // 'angular velocity' here)
  theta += 0.2;

  // For every x value, calculate a y value with sine function
  let x = theta;
  for (let i = 0; i < yvalues.length; i++) {
    yvalues[i] = sin(x) * amplitude;
    x += dx;
  }
}

function renderWave(yPos) {
  noStroke();
  beginShape();
  vertex(0,height);
  // A simple way to draw the wave with an ellipse at each location
  for (let x = 0; x <= yvalues.length; x++) {
    vertex(x * xspacing, yPos + yvalues[x])
  }
  vertex(width,height);
  endShape(CLOSE);
}










Leave a Reply