# Final Project

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

{
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);
pop();
}

function makeBuilding(birthLocationX)
{
var bldg = {x: birthLocationX,
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,
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,
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();
}

{
fill(0);
rect (530, 550, 90, 40);
fill(255);
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
{
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,
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”.