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