Our project is inspired by the game Flappy Bird. In our rendition, 2020 events are the obstacles on the pipes and the goal is to “survive” 2020. The character moves up when you hit the letter ‘m’, the game ends if you hit one of the pipes, hit the ground or if you win by passing 12 pairs of pipes. If you lose by hitting a pipe or win you can play the game again, but if you hit the ground you lose and cannot restart the game. The two sounds you hear are the bounce when you move the character and the clash when the character hits one of the pipes. Based on which pipe you hit, you see a different “game over” message. We chose a darker color scheme and used a fire in the background to match the mood of 2020. If we had more time with this project, we would add a webcam function so that the character would be the user’s face instead of just a smiley face. Overall, this project was definitely challenging but also really fun to create.
/*
* Final Project
* Rishi Karthikeyan and Amy Lee
* rkarthik and amyl2
* Section B
*/
// Run a local server to hear sounds used
// Press the letter m to control character
// The game ends if the character hits the ground or the pipes
// If you lose by hitting a pipe or win you can play the game again
// but if you hit the ground you lose and cannot restart the game
var score = 0;
var count = 0;
var faceX = 50;
var faceY = 200;
var hitPipe = false;
var endGame = false;
var gameOn = true;
var gameStart = true;
var characterOn = true;
var pipes = [];
var fire = [];
var pipeImages = []; // an array to store the images
var factImages = []; // an array to store the dates between the pipes
var gameOverImages = []; // an array to store the customized game over images
var timeline1 = ["1/1/20", "1/16/20", "1/19/20", "2/2/20", "3/11/20",
"3/19/20", "3/20/20", "4/1/20", "5/1/20", "5/26/20", "11/6/20", "11/7/20"]
var timeline2=["Australian Bush Fire","Trump Impeached","COVID-19","Superbowl",
"Parasite Wins Oscars","Zoom University","Tiger King","Royal Family Split",
"Murder Hornets", "BLM Movement", "Election", "First Female VP Elect"]
function preload() {
// Circular images that go in the pipes
var filenames = [];
filenames[0] = "https://i.imgur.com/tP1n00I.png"; // Fire
filenames[1] = "https://i.imgur.com/sY9uWvm.png"; // Trump
filenames[2] = "https://i.imgur.com/lCBeEEt.png"; // Covid
filenames[3] = "https://i.imgur.com/3Rckn2m.png"; // Superbowl
filenames[4] = "https://i.imgur.com/ul9jOdN.png"; // Oscar
filenames[5] = "https://i.imgur.com/iWRAmux.png"; // Zoom
filenames[6] = "https://i.imgur.com/dbYhauj.png"; // Tiger King
filenames[7] = "https://i.imgur.com/lVbGhGa.png"; // Meg and Harry
filenames[8] = "https://i.imgur.com/U1PoDE5.png"; // Hornets
filenames[9] = "https://i.imgur.com/nqwizdc.png"; // BLM
filenames[10] = "https://i.imgur.com/xtEZvMR.png"; // Election
filenames[11] = "https://i.imgur.com/1lZjhEQ.png"; // Kamala
for (var i = 0; i < filenames.length; i ++) {
pipeImages.push(loadImage(filenames[i]));
}
// Displays game over message based on which pipe the character dies on
var filenames2 = [];
filenames2[0] = "https://i.imgur.com/ibfDcOO.png"; // Fire
filenames2[1] = "https://i.imgur.com/vFpcofS.png"; // Trump
filenames2[2] = "https://i.imgur.com/NMyD9W2.png"; // Covid
filenames2[3] = "https://i.imgur.com/aU3iUST.png"; // Superbowl
filenames2[4] = "https://i.imgur.com/hqLtxr4.png"; // Oscar
filenames2[5] = "https://i.imgur.com/59MSAMG.png"; // Zoom
filenames2[6] = "https://i.imgur.com/ArzVHYU.png"; // Tiger King
filenames2[7] = "https://i.imgur.com/up0miQL.png"; // Meg and Harry
filenames2[8] = "https://i.imgur.com/pSRx5bC.png"; // Hornets
filenames2[9] = "https://i.imgur.com/EzfHYCr.png"; // BLM
filenames2[10] = "https://i.imgur.com/wJvHY17.png"; // Election
filenames2[11] = "https://i.imgur.com/929AM73.png"; // Kamala
for (var i = 0; i < filenames2.length; i ++) {
gameOverImages.push(loadImage(filenames2[i]));
}
// Load sounds for when the character moves or hits the pipes
characterSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/bounce.wav");
clashSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/clash.wav");
}
function setup() {
createCanvas(450, 400);
background(12, 22, 24);
imageMode(CENTER);
useSound();
if (gameOn == true) {
fire.push(makeFire());
pipes.push(makePipes());
}
}
function soundSetup() {
// Set the volume for the sound effects
characterSound.setVolume(0.01);
clashSound.setVolume(0.05);
}
function draw() {
background(12, 22, 24);
gradientSky();
if (gameOn == true) {
// Start the count once the game is on
count++
// Display & add fire
updateAndDisplayFire();
if (count % 50 == 10){
fire.push(makeFire());
}
updateAndDisplayPipes();
// Add new pipes
if (count % 120 == 0){
if (gameOn == true) {
}
if (pipes.length < 12) {
pipes.push(makePipes());
}
if (count > 300) {
score += 150;
}
}
}
// Score tracker
textSize(15);
fill(72,160,141);
noStroke();
text('SCORE ' + score, 50, 23);
drawFace();
if (count >= 1690){
gameOn = false;
}
if (gameOn == false) {
gameWon();
}
if (hitPipe == true){
gameOver(round((count/120) - ((120*3)/120)));
}
}
function gradientSky() {
// Background color gradient
var darkCol = color(0,12,15);
var lightCol = color(14,38,39);
for (var y = 0; y < height; y ++){
var backG = map(y, 0, height, 0, 1);
var backGColor = lerpColor(darkCol, lightCol, backG);
stroke(backGColor);
line(0, y, width, y);
}
// Fire Embers
for (var i = 0; i < 35; i++) {
strokeWeight(4);
if (round(random(1)) == 0 ) {
stroke(148, 67, 43);
} else {
stroke(81, 33, 22);
}
point(random(0,width), random(-0, height));
}
}
// *************** FIRES *************** //
function updateAndDisplayFire(){
// Update the fire's positions, and display them.
for (var i = 0; i < fire.length; i++){
fire[i].move();
fire[i].draw();
}
}
// Method to update position of fire every frame
function fireMove() {
this.x += this.speed;
}
// Draw the fire
function fireDraw() {
push();
translate(0, height - 220);
scale(1.2, 1.75);
noStroke();
fill(81, 33, 22); //red fire
beginShape();
vertex(this.x, this.y + 125);
vertex(this.x, this.y + 115);
vertex(this.x + 5, this.y + 115);
curveVertex(this.x + 4, this.y + 113);
curveVertex(this.x + 3, this.y + 112);
curveVertex(this.x + 3, this.y + 108);
curveVertex(this.x + 5, this.y + 102);
curveVertex(this.x + 9, this.y + 98);
vertex(this.x + 18 + random(-1, 1), this.y + 93+ random(-1, 1));
curveVertex(this.x + 17, this.y + 110);
curveVertex(this.x + 21, this.y + 112);
curveVertex(this.x + 31, this.y + 109);
curveVertex(this.x + 31, this.y + 102);
curveVertex(this.x + 25, this.y + 95);
curveVertex(this.x + 24, this.y + 89);
curveVertex(this.x + 27, this.y + 83);
curveVertex(this.x + 34, this.y + 77);
curveVertex(this.x + 40, this.y + 70);
curveVertex(this.x + 34, this.y + 56);
vertex(this.x + 30 + random(-1, 1), this.y + 53 + random(-1, 1));
curveVertex(this.x + 40, this.y + 56);
curveVertex(this.x + 50, this.y + 64);
curveVertex(this.x + 48, this.y + 75);
curveVertex(this.x + 41, this.y + 83);
curveVertex(this.x + 38, this.y + 90);
curveVertex(this.x + 40, this.y + 98);
curveVertex(this.x + 49, this.y + 99);
curveVertex(this.x + 52, this.y + 95);
curveVertex(this.x + 48, this.y + 90);
curveVertex(this.x + 48, this.y + 84);
vertex(this.x + 55 + random(-1, 1), this.y + 75 + random(-1, 1));
curveVertex(this.x + 54, this.y + 81);
curveVertex(this.x + 56, this.y + 89);
curveVertex(this.x + 60, this.y + 97);
curveVertex(this.x + 56, this.y + 104);
curveVertex(this.x + 62, this.y + 117);
curveVertex(this.x + 72, this.y + 118);
curveVertex(this.x + 80, this.y + 112);
curveVertex(this.x + 75, this.y + 99);
curveVertex(this.x + 68, this.y + 92);
curveVertex(this.x + 63, this.y + 83);
curveVertex(this.x + 70, this.y + 63);
curveVertex(this.x + 84, this.y + 54);
vertex(this.x + 94 + random(-1, 1), this.y + 50 + random(-1, 1));
curveVertex(this.x + 85, this.y + 56);
curveVertex(this.x + 77, this.y + 65);
curveVertex(this.x + 73, this.y + 73);
curveVertex(this.x + 77, this.y + 77);
curveVertex(this.x + 87, this.y + 75);
vertex(this.x + 89 + random(-1, 1), this.y + 63 + random(-1, 1));
curveVertex(this.x + 93, this.y + 68);
curveVertex(this.x + 93, this.y + 78);
curveVertex(this.x + 87, this.y + 86);
curveVertex(this.x + 81, this.y + 93);
curveVertex(this.x + 87, this.y + 99);
curveVertex(this.x + 92, this.y + 99);
curveVertex(this.x + 97, this.y + 92);
curveVertex(this.x + 94, this.y + 87);
curveVertex(this.x + 94, this.y + 84);
vertex(this.x + 98 + random(-1, 1), this.y + 77 + random(-1, 1));
curveVertex(this.x + 101, this.y + 85);
curveVertex(this.x + 104, this.y + 89);
curveVertex(this.x + 107, this.y + 97);
curveVertex(this.x + 104, this.y + 104);
curveVertex(this.x + 101, this.y + 110);
curveVertex(this.x + 109, this.y + 115);
vertex(this.x + 113, this.y + 115);
vertex(this.x + 113, this.y + 128);
endShape(CLOSE);
pop();
push();
translate(0, height - 125);
scale(1, 1);
noStroke();
fill(148, 67, 43); //orange fire
beginShape();
vertex(this.x, this.y + 125);
vertex(this.x, this.y + 115);
vertex(this.x + 5, this.y + 115);
curveVertex(this.x + 4, this.y + 113);
curveVertex(this.x + 3, this.y + 112);
curveVertex(this.x + 3, this.y + 108);
curveVertex(this.x + 5, this.y + 102);
curveVertex(this.x + 9, this.y + 98);
vertex(this.x + 18 + random(-1, 1), this.y + 93+ random(-1, 1));
curveVertex(this.x + 17, this.y + 110);
curveVertex(this.x + 21, this.y + 112);
curveVertex(this.x + 31, this.y + 109);
curveVertex(this.x + 31, this.y + 102);
curveVertex(this.x + 25, this.y + 95);
curveVertex(this.x + 24, this.y + 89);
curveVertex(this.x + 27, this.y + 83);
curveVertex(this.x + 34, this.y + 77);
curveVertex(this.x + 40, this.y + 70);
curveVertex(this.x + 34, this.y + 56);
vertex(this.x + 30 + random(-1, 1), this.y + 53 + random(-1, 1));
curveVertex(this.x + 40, this.y + 56);
curveVertex(this.x + 50, this.y + 64);
curveVertex(this.x + 48, this.y + 75);
curveVertex(this.x + 41, this.y + 83);
curveVertex(this.x + 38, this.y + 90);
curveVertex(this.x + 40, this.y + 98);
curveVertex(this.x + 49, this.y + 99);
curveVertex(this.x + 52, this.y + 95);
curveVertex(this.x + 48, this.y + 90);
curveVertex(this.x + 48, this.y + 84);
vertex(this.x + 55 + random(-1, 1), this.y + 75 + random(-1, 1));
curveVertex(this.x + 54, this.y + 81);
curveVertex(this.x + 56, this.y + 89);
curveVertex(this.x + 60, this.y + 97);
curveVertex(this.x + 56, this.y + 104);
curveVertex(this.x + 62, this.y + 117);
curveVertex(this.x + 72, this.y + 118);
curveVertex(this.x + 80, this.y + 112);
curveVertex(this.x + 75, this.y + 99);
curveVertex(this.x + 68, this.y + 92);
curveVertex(this.x + 63, this.y + 83);
curveVertex(this.x + 70, this.y + 63);
curveVertex(this.x + 84, this.y + 54);
vertex(this.x + 94 + random(-1, 1), this.y + 50 + random(-1, 1));
curveVertex(this.x + 85, this.y + 56);
curveVertex(this.x + 77, this.y + 65);
curveVertex(this.x + 73, this.y + 73);
curveVertex(this.x + 77, this.y + 77);
curveVertex(this.x + 87, this.y + 75);
vertex(this.x + 89 + random(-1, 1), this.y + 63 + random(-1, 1));
curveVertex(this.x + 93, this.y + 68);
curveVertex(this.x + 93, this.y + 78);
curveVertex(this.x + 87, this.y + 86);
curveVertex(this.x + 81, this.y + 93);
curveVertex(this.x + 87, this.y + 99);
curveVertex(this.x + 92, this.y + 99);
curveVertex(this.x + 97, this.y + 92);
curveVertex(this.x + 94, this.y + 87);
curveVertex(this.x + 94, this.y + 84);
vertex(this.x + 98 + random(-1, 1), this.y + 77 + random(-1, 1));
curveVertex(this.x + 101, this.y + 85);
curveVertex(this.x + 104, this.y + 89);
curveVertex(this.x + 107, this.y + 97);
curveVertex(this.x + 104, this.y + 104);
curveVertex(this.x + 101, this.y + 110);
curveVertex(this.x + 109, this.y + 115);
vertex(this.x + 113, this.y + 115);
vertex(this.x + 113, this.y + 128);
endShape(CLOSE);
pop();
}
function makeFire() {
var fire = {x: width,
y: 0,
speed: -2,
move: fireMove,
draw: fireDraw}
return fire;
}
// *************** CHARACTER *************** //
function drawFace() {
if (characterOn == true) {
push();
// Head
noStroke();
fill(72,160,141);
ellipse(faceX, faceY, 30, 30);
// Eyes
fill(12, 22, 24);
ellipse(faceX - 9, faceY - 1, 3.5, 3.5);
ellipse(faceX + 9, faceY - 1, 3.5, 3.5);
// Mouth
noFill();
stroke(12, 22, 24);
strokeWeight(1);
arc(faceX, faceY, 5, 5, 0, PI, OPEN);
pop();
faceY += 1;
// Keep face from going off of the canvas
if (faceY < 15){
faceY += 5;
}
// Game over if you hit the bottom of the canvas
if (faceY > height - 15){
hitBottomGameOver();
}
}
}
// *************** PIPES *************** //
function updateAndDisplayPipes(){
// Update the pipe's positions, and display them
for (var i = 0; i < pipes.length; i++) {
pipes[i].move();
// Game over if face hits the pipes
if (((faceY < pipes[i].pipeHeight + 30) & (faceX > pipes[i].x &&
faceX < pipes[i].x + pipes[i].pipeWidth)) || ((faceY > 400 -
((400 - (pipes[i].pipeHeight + (200 - pipes[i].pipeHeight) +
(122 - (200 - pipes[i].pipeHeight)))) + 55)) &&
(faceX > pipes[i].x && faceX < pipes[i].x + pipes[i].pipeWidth))){
hitPipe = true;
clashSound.play();
}
if (gameStart == true) {
pipes[i].draw();
}
// Display image on pipe
pipes[i].imageNumber = i;
if ( pipes[i].imageNumber > 11) {
pipes[i].imageNumber = 0;
}
// Display timeline date in between pipes
pipes[i].timelineNumber = i;
if ( pipes[i].timelineNumber > 11) {
pipes[i].timelineNumber = 0;
}
}
}
// Method to update position of pipe every frame
function pipesMove() {
this.x += this.speed;
}
// Draw the pipe
function pipesDraw() {
var pipe1Height = this.pipeHeight - 30;
var pipe2Height = 400 - (this.pipeHeight + (200 - this.pipeHeight) +
(126 - (200 - this.pipeHeight)) );
fill(34,79,82);
noStroke();
// Top Pipe
rect(this.x, -30, this.pipeWidth, this.pipeHeight);
ellipse(this.x + 40, pipe1Height, this.pipeWidth, this.pipeWidth);
image(pipeImages[this.imageNumber], this.x + 40, pipe1Height, 60, 60);
// Fact in middle of pipe
textSize(15);
textAlign(CENTER);
fill(148, 67, 43);
text(timeline1[this.timelineNumber], this.x + 40, (pipe1Height +
((400 - ((pipe1Height) + (pipe2Height)))/2)) - 2);
text(timeline2[this.timelineNumber], this.x + 40, (pipe1Height +
((400 - ((pipe1Height) + (pipe2Height)))/2)) + 15);
// Bottom Pipe
push();
fill(34,79,82);
translate(0,400);
rect(this.x, -pipe2Height, this.pipeWidth, pipe2Height);
ellipse(this.x + 40, -pipe2Height, this.pipeWidth, this.pipeWidth);
image(pipeImages[this.imageNumber], this.x + 40, -pipe2Height, 60, 60);
pop();
}
function makePipes() {
var pipe = {x: 650,
pipeWidth: 80,
pipeHeight: random(130, 200),
speed: -2,
move: pipesMove,
draw: pipesDraw,
imageNumber: 0,
timelineNumber: 0
}
return pipe;
}
function keyPressed() {
if (key == 'm'){
faceY -= 20;
if (characterOn == true) {
characterSound.play();
}
}
}
// Function that is run when character hits the bottom of the canvas
function hitBottomGameOver() {
push();
gradientSky();
noStroke();
fill(72,160,141);
rectMode(CENTER);
rect(width/2, height/2, 227, 55);
textAlign(CENTER);
textSize(20);
fill(148, 67, 43);
text(' Y O U L O S T 2 0 2 0 ! ', width/2, height/2);
characterOn = false;
noLoop();
pop();
}
// Function that is run when the character hits the pipe
function gameOver(pipeNumber){
// Display the gradient sky
gradientSky();
// Display game over image depending on which pipe was hit
image(gameOverImages[pipeNumber], width/2, height/2, 250, 250);
// Display play again button
fill(148, 67, 43);
stroke(180, 67, 43);
strokeWeight(2);
push();
rectMode(CENTER);
rect(width/2, height/2 + 160, 110, 35);
pop();
textSize(15);
noStroke();
fill(255);
text('PLAY AGAIN', width/2, height/2 + 165);
gameStart = false;
characterOn = false;
hitPipe = true;
gameOn = false;
}
// Function that is run when the character wins the entire game
function gameWon() {
push();
// "YOU WON 2020" sign in center of screen
noStroke();
fill(72,160,141);
rectMode(CENTER);
rect(width/2, height/2, 225, 55);
textAlign(CENTER);
textSize(20);
fill(148, 67, 43);
text(' Y O U W O N 2 0 2 0 ! ', width/2, height/2);
// Play again button
fill(148, 67, 43);
stroke(180, 67, 43);
strokeWeight(2);
rect(width/2, height/2 + 55, 110, 35);
textSize(15);
noStroke();
fill(255);
text('PLAY AGAIN', width/2, height/2 + 55);
characterOn = false;
pop();
}
function mousePressed() {
// Press to play again after a user wins the game
if (count >= 1689 & gameOn == false) {
if (mouseX > width/2 - 55 && mouseX < width/2 + 55 &&
mouseY < height/2 + 72.5 && mouseY > height/2 + 37.5) {
gameOn = true;
gameStart = true;
characterOn = true;
endGame = false;
count = -50;
score = 0;
pipes = [];
fire = [];
}
}
// Press to play again when user lost the game by hitting a pipe
if (hitPipe == true) {
if (mouseX > width/2 - 55 & mouseX < width/2 + 55 &&
mouseY < height/2 + 177.5 && mouseY > height/2 + 142.5) {
hitPipe = false;
endGame = false;
gameStart = true;
gameOn = true;
characterOn = true;
count = -50;
score = 0;
pipes = [];
fire = [];
}
}
}
***on our Autolab submission we use the up arrow to control the character but here we used the letter m because with the up arrow it would move the whole page up and not just the canvas***
]]>var highMountain = [];
var lowMountain = [];
var cabin = [];
var trees = [];
var dogImage = [];
var dog = [];
var noiseParam = 0;
var noiseStep = 0.01;
function preload(){
var filenames = [];
filenames[0] = "https://i.imgur.com/KGHR8lv.png";
filenames[1] = "https://i.imgur.com/KGHR8lv.png";
filenames[2] = "https://i.imgur.com/unhcm3R.png";
filenames[3] = "https://i.imgur.com/unhcm3R.png";
filenames[4] = "https://i.imgur.com/J2pZbow.png";
filenames[5] = "https://i.imgur.com/J2pZbow.png";
filenames[6] = "https://i.imgur.com/unhcm3R.png";
filenames[7] = "https://i.imgur.com/unhcm3R.png";
for (var i = 0; i<filenames.length; i++) {
dogImage[i] = loadImage(filenames[i]);
}
}
function setup() {
createCanvas(480, 240);
frameRate(24);
imageMode(CENTER);
//mountains
for (var i = 0; i <= width/4; i++) {
var value = map(noise(noiseParam), 0, 1, 0, height*1.1);
highMountain.push(value);
noiseParam += noiseStep;
}
for (var i = 0; i <= width/5; i++) {
var value = map(noise(noiseParam), 0, 1, 0, height*1.9);
lowMountain.push(value);
noiseParam += noiseStep;
}
// create an initial collection of cabins
for (var i = 0; i < 10; i++){
var rx = random(width);
cabin[i] = makeCabin(rx);
var r = random(width);
trees[i] = makeTree(r);
}
//create three walking characters
var d = makeCharacter(400, 200);
dog.push(d);
}
function draw() {
background(200);
//sky as a gradient
var gradPurple = color(134, 123, 198);
var gradPink = color(240, 198, 209);
for (var i = 0; i < height; i++){
var gradient = map (i, 0, (height/3)*1.5, 0, 1);
var bgColor = lerpColor(gradPurple, gradPink, gradient);
stroke(bgColor);
line(0, i, width, i);
}
//snow
stroke(239, 241, 253);
strokeWeight(2);
for (var i = 0; i < 750; i++) {
point(random(0,width), random(-0, height));
}
//sun
noStroke();
fill(242, 226, 233, 90);
circle(width/2, height/2-40, 60);
fill(242, 226, 233, 75);
circle(width/2, height/2-40, 50);
fill(242, 226, 233, 60);
circle(width/2, height/2-40, 40);
fill(242, 226, 233);
circle(width/2, height/2-40, 30);
//clouds
cloud(45, 80);
cloud(180, 130);
cloud(360, 160);
cloud(445, 70);
//mountains
drawHighMountain();
drawLowMountain();
//snow on the ground
fill(239, 241, 253);
rect(0, 180, width, 60);
//trees
updateAndDisplayTrees();
removeTreesThatHaveSlippedOutOfView();
addNewTreesWithSomeRandomProbability();
//cabins
updateAndDisplayCabins();
removeCabinsThatHaveSlippedOutOfView();
addNewCabinsWithSomeRandomProbability();
//walking dog
for (var i = 0; i < dog.length; i++) {
var d = dog[i];
d.stepFunction();
d.drawFunction();
}
//fence
for (var x = 10; x <= width-10; x+=10) {
stroke(198, 173, 203);
strokeWeight(5);
line(x, height, x, height-25);
}
line(0, height-15, width, height-15);
}
function drawHighMountain() {
highMountain.shift();
var value = map(noise(noiseParam), 0, 1, 0, height*1.1);
highMountain.push(value);
noiseParam += noiseStep;
push();
fill(170, 190, 250);
stroke(170, 190, 250);
beginShape();
vertex(0, height);
for (var i = 0; i < width/4; i++) {
vertex(i*5, highMountain[i]);
vertex((i+1)*5, highMountain[i+1]);
}
vertex(width, height);
endShape();
pop();
}
function drawLowMountain() {
lowMountain.shift();
var value = map(noise(noiseParam), 0, 1, 0, height*1.9);
lowMountain.push(value);
noiseParam += noiseStep;
push();
fill(193, 205, 246);
stroke(193, 205, 246);
beginShape();
vertex(0, height);
for (var i = 0; i < width/5; i++) {
vertex(i*5, lowMountain[i]);
vertex((i+1)*5, lowMountain[i+1]);
}
vertex(width, height);
endShape();
pop();
}
//cabins
function makeCabin(birthLocationX) {
var bldg = {x: birthLocationX,
breadth: 70,
speed: -5.0,
nFloors: round(random(2,8)),
move: cabinMove,
display: cabinDisplay}
return bldg;
}
// method to update position of cabin every frame
function cabinMove() {
this.x += this.speed;
}
// draw the cabin and some windows
function cabinDisplay() {
var floorHeight = 8;
var cHeight = this.nFloors * floorHeight;
noStroke();
fill(95, 124, 213);
push();
translate(this.x, height - 40);
//chimmney
rect(this.breadth-10, -cHeight - 20, 10, 15);
//roof
stroke(239, 241, 253);
triangle(-7,-cHeight,this.breadth/2,-cHeight-20,this.breadth+7,-cHeight);
//home
stroke(95, 124, 213);
rect(0, -cHeight, this.breadth, cHeight);
fill(239, 241, 253);
noStroke();
circle(this.breadth/2, -cHeight - 10, 10);
rect(this.breadth-10, -cHeight - 20, 10, 5);
//windows
fill(148, 178, 249);
stroke(95, 124, 213);
for (var i = 0; i < this.nFloors-1; i++) {
rect(5, -15 - (i * floorHeight), this.breadth - 10, 10);
}
pop();
}
function updateAndDisplayCabins(){
// Update the cabin's positions, and display them.
for (var i = 0; i < cabin.length; i++){
cabin[i].move();
cabin[i].display();
}
}
function removeCabinsThatHaveSlippedOutOfView(){
var cabinToKeep = [];
for (var i = 0; i < cabin.length; i++){
if (cabin[i].x + cabin[i].breadth > 0) {
cabinToKeep.push(cabin[i]);
}
}
cabin = cabinToKeep; // remember the surviving cabin
}
function addNewCabinsWithSomeRandomProbability() {
// With a very tiny probability, add a new cabin to the end.
var newCabinLikelihood = 0.01;
if (random(0,1) < newCabinLikelihood) {
cabin.push(makeCabin(width));
}
}
// dog walking character
function makeCharacter(cx, cy) {
c = {x: cx, y: cy,
imageNumber: 0,
stepFunction: characterStep,
drawFunction: characterDraw
}
return c;
}
function characterStep() {
this.imageNumber++;
if (this.imageNumber == 8) {
this.imageNumber = 0;
}
}
function characterDraw() {
image(dogImage[this.imageNumber], this.x, this.y);
}
// trees
function makeTree(birthLocationX) {
var t = {x: birthLocationX,
breadth: round(random(20,30)),
speed: -5.0,
treeHeight: round(random(30,70)),
move: treeMove,
display: treeDisplay}
return t;
}
function treeMove() {
this.x += this.speed;
}
function treeDisplay() {
push();
translate(this.x, height - 60);
noStroke();
fill(153, 139, 196);
rect(-2, 0, 6, 8);
fill(242, 198, 210);
triangle(0, 0, 0, -this.treeHeight, -this.breadth/2, 0);
fill(223, 186, 209);
triangle(0, 0, 0, -this.treeHeight, this.breadth/2, 0);
stroke(225);
line(0, 0, 0, -this.treeHeight);
pop();
}
function updateAndDisplayTrees(){
for (var i = 0; i < trees.length; i++){
trees[i].move();
trees[i].display();
}
}
function removeTreesThatHaveSlippedOutOfView(){
var treesToKeep = [];
for (var i = 0; i < trees.length; i++){
if (trees[i].x + trees[i].breadth > 0) {
treesToKeep.push(trees[i]);
}
}
trees = treesToKeep;
}
function addNewTreesWithSomeRandomProbability() {
var newTreeLikelihood = 0.07;
if (random(0,1) < newTreeLikelihood) {
trees.push(makeTree(width));
}
}
function cloud(x, y) {
fill(239, 241, 253, 50);
arc(x, y, 60, 40, PI + TWO_PI, TWO_PI);
arc(x + 30, y, 90, 90, PI + TWO_PI, TWO_PI);
arc(x + 25, y, 40, 70, PI + TWO_PI, TWO_PI);
arc(x + 50, y, 70, 40, PI + TWO_PI, TWO_PI);
}
For this project, I wanted to created a snowy landscape. I started by drawing two layers of mountains and then added the cabins, the trees, and the running dog. I feel like the cool tone color palette contrasts really well with the dog. The sun and clouds looked pretty plain so I played with the opacity of the shapes to create some visual interest. The hardest part was figuring out how to do the gradient, but I’m happy with the way that it turned out and the way it looks with the snow! I didn’t want to overcrowd the piece too much so the last thing I added was a fence.
Yael Braha is a large-scale dynamic display designer. Braha combines traditional and non-traditional art to creates pieces that combine fine arts and digital fabrication. Braha studied Graphic Design at the European Institute of Design in Rome. After immigrating to the US, she got a Masters of Fine Arts in Cinema at San Francisco State University. Her work has been displayed all across the world for 20 years and is currently based out of Canada.
Braha and her team created Tree of Changes, using 3d-modeling, custom machine learning programs, and fabrication, for the Yerba Buena Center for the Arts for the 2015 Market Street Prototyping Festival. This piece is an interactive sculpture that creates light patterns based on the viewers voice. I admire how this piece speaks to people of all ages because it highlights how Braha’s artistic sensibilities show up in her work. Braha notes her work is inspired by her roots as the daughter of refugees which taught her to value knowledge over belongings. With this piece she not only creates universal interest but also provides them with insight on how cutting-edge technology is being used to create art today. I also admire the aesthetic of the piece in contrast with the night sky.
]]>// Rishi Karthikeyan
//rkarthik@andrew.cmu.edu
//Section B
//HW 10 Sonic Story
let elf;
var elfX = 350; var elfY = 225;
let santa;
var santaX = 115; var santaY = 225;
let santaWorkshop;
let santaAndReindeer;
var santaAndReindeerX = 160; var santaAndReindeerY = 250;
let santaOnChimney;
let kid;
var kidX = 100; var kidY = 275;
let tree;
let elfVoice;
let sleighBells;
let santaVoice;
let kidVoice;
var count = 0;
var centerX = 250;
var centerY = 200;
var dx = 30;
var dy = 5;
function preload() {
//load images
elf = loadImage('https://i.imgur.com/pu8ed6l.png');
santa = loadImage('https://i.imgur.com/5rgNTe1.png');
santaWorkshop =loadImage('https://i.imgur.com/bmjFtUd.png');
santaAndReindeer = loadImage('https://i.imgur.com/t86lPuw.png');
santaOnChimney = loadImage('https://i.imgur.com/NoL1xBz.png');
kid = loadImage('https://i.imgur.com/F06Ekzc.png');
tree = loadImage('https://i.imgur.com/qOOQlZt.png');
//load sounds
elfVoice = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/ElfVoice.wav");
sleighBells = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/SleighBells.wav");
santaVoice = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/SantaVoice.wav");
kidVoice = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/KidVoice.wav");
}
function setup() {
createCanvas(500, 400);
//createDiv("p5.dom.js library is loaded.");
useSound();
imageMode(CENTER);
frameRate(1);
}
function soundSetup() {
elfVoice.setVolume(0.5);
sleighBells.setVolume(0.5);
santaVoice.setVolume(0.5);
kidVoice.setVolume(0.5);
}
function draw() {
background(200);
count++;
switch (count) {
case 1: elfVoice.play(); break;
case 6: sleighBells.play(); break;
case 11: santaVoice.play(); break;
case 16: kidVoice.play(); break;
}
if (count >= 0 & count < 5) {
workshop();
dy = 10;
elfY -= dy;
if ( elfY <= 215) {
elfY +=20;
}
}
if (count >= 5 & count < 10) {
reindeer();
dy = 20;
santaAndReindeerX += dx;
santaAndReindeerY -= dy;
}
if (count >= 10 & count < 15) {
chimney();
centerY += dy;
}
if (count >= 15 & count < 20) {
home();
kidY -= 5;
if ( kidY <= 270) {
kidY +=10;
}
}
if (count >=20) {
end();
}
}
function workshop() {
nightSky();
//snow
fill(255);
rect(0, 215, width, 200);
image(santaWorkshop, centerX+80, centerY-30, 300, 100);
image(elf, elfX, elfY, 130, 130);
image(santa, santaX, santaY, 206, 200);
}
function reindeer() {
nightSky();
//moon
noStroke();
fill(208);
circle(centerX, centerY-30, 200);
//mountains
fill(20, 28, 38);
beginShape();
vertex(0, height);
vertex(0, 270);
vertex(105, 225);
vertex(205, 300);
vertex(290, 250);
vertex(350, 280);
vertex(450, 205);
vertex(width, 225);
vertex(width, height);
endShape(CLOSE);
image(santaAndReindeer, santaAndReindeerX, santaAndReindeerY, 270, 225);
}
function chimney() {
nightSky();
//roof
image(santaOnChimney, centerX, centerY, 230, 230);
noStroke();
fill(195, 70, 55);
rect(0, 315, width, 85);
}
function home() {
nightSky();
//wall
noStroke();
fill(224, 193, 173);
rect(0, 0, width, 50);
rect(0, 0, 50, height);
rect(250, 0, 250, height);
rect(0, 150, width, 200);
//floor
fill(225, 221, 207);
rect(0, 300, width, 100);
//window
strokeWeight(5);
stroke(255);
noFill();
rect(50, 50, 100, 100);
rect(150, 50, 100, 100);
strokeWeight(2);
line(50, 100, 250, 100);
line(100, 50, 100, 150);
line(200, 50, 200, 150);
image(kid, kidX, kidY, 150, 125);
image(tree, 340, 220, 300, 300);
}
function end() {
nightSky();
noStroke();
fill(255);
textSize(50);
text('The End', 185, 250);
}
function nightSky() {
//night sky
background(6, 20, 34);
//stars
stroke(255);
for (var i = 0; i < 1000; i++) {
point(random(0,width), random(-0, height));
}
}
Four Sounds (1) elf singing (2) sleigh bells (3) Santa talking (4) kid celebrating
I wanted to make something Christmas related. This story shows Santa delivering presents. This project was a lot of fun to create and helped me better understand how to code with images and sound.
]]>Computer Orchestra was created in 2013 by Fragment.in, an artist collective comprised of Laura Perrenoud, David Colombini and Marc Dubois. They used Processing, SimpleOpenNI, and OpenKinect to create this project. Computer Orchestra is an interactive installation that uses multiple computers to allow the user to conduct their own orchestra. Their hand movements are recognized by a Kinect motion controller that transmits data to Processing through the SimpleOpenNI library. Processing then sends a signal to the main computer which gives instructions to the rest of the screens.
I admire how this piece is made to be accessible. Computer Orchestra crowdsources sounds to use and users can upload their own sounds as well. I also admire that there is a visual component to the project, along with the sound the program creates aesthetically pleasing sound waves on the screen that enhance the experience. It’s amazing to see how just one person can create the feel of an entire orchestra.
Fragment.in states that they use their work as a way to question the impact of the digital on everyday life. These artistic sensibilities are seen in Computer Orchestra through the way it highlights how one person can replace an entire orchestra with the use of digital.
]]>let portrait;
var radius = 0;
var angle = 0;
var framecount = 1;
var size = 0.5;
function preload() {
portrait = loadImage('https://i.imgur.com/EquKB8x.png');
}
function setup() {
createCanvas(480, 480);
background(0);
imageMode(CENTER);
portrait.loadPixels();
}
function draw() {
var centerX = width/2;
var centerY = height/2;
var circleX = radius * cos(radians(angle));
var circleY = radius * sin(radians(angle));
var clrX = random(0, width);
var clrY = random(0, height);
var clr = portrait.get(clrX, clrY);
//pointillize
for (var i= 0; i < 10; i++) {
fill(clr);
circle(clrX, clrY, size);
}
//top left spiral of hearts of image
noStroke();
var clr1 = portrait.get(circleX, circleY);
fill(clr1);
drawHeart(circleX, circleY, 15);
//bottom right spiral of hearts of image
push();
translate(centerX, centerY);
var clr2 = portrait.get(480-circleX, 480-circleY);
fill(clr2);
drawHeart(centerX-circleX, centerY-circleY, 15);
pop();
topInstagramBar();
bottomInstagramBar();
radius += 0.1;
angle += 7;
frameCount += 1;
if (frameCount > 13000) {
//"instagram tag" of my nickname where mouse is
fill(85);
triangle(mouseX, mouseY-10, mouseX+10, mouseY-20, mouseX-10, mouseY-20);
rect(mouseX-40, mouseY-40, 80, 20);
fill(255);
text('rishdish', mouseX-20, mouseY-27);
//stops when portrait is complete
noLoop();
}
}
function drawHeart(x, y, s) {
beginShape();
vertex(x,y);
bezierVertex(x-s/2, y-s/2, x-s, y+s/3, x, y+s);
bezierVertex(x+s, y+s/3, x+s/2, y-s/2, x, y);
endShape(CLOSE);
}
function mousePressed() {
//points get bigger as you click
size += 0.5;
if (size == 7) {
size = 0.5;
}
}
function topInstagramBar() {
//instagram bar
fill(240);
rect(0, 0, 480, 30);
//profile pic
fill(230, 210, 210);
circle(20, 15, 15);
stroke(195, 45, 140);
noFill();
circle(20, 15, 18);
noStroke();
fill(0);
text('15-104',35, 19);
//three dots in right hand corner
fill(10);
circle(455, 15, 3);
circle(460, 15, 3);
circle(465, 15, 3);
}
function bottomInstagramBar() {
//instagram bar
fill(240);
rect(0, 450, 480, 30);
//"like" icon
stroke(0);
fill(255);
drawHeart(20, 460, 15);
//"comment" icon
triangle(53, 471, 60, 471, 58, 467);
circle(50, 465, 16);
stroke(255);
circle(55, 468, 5);
//"share" icon
stroke(0);
triangle(75, 457, 92, 457, 80, 463);
triangle(80, 463, 92, 458, 82,472);
//"save"icon
beginShape();
vertex(454, 457);
vertex(454, 472);
vertex(460, 467);
vertex(466, 472);
vertex(466, 457);
endShape(CLOSE);
//image scroll through icons
noStroke();
fill(65, 141, 204);
circle(230, 465, 5);
fill(165);
circle(240, 465, 5);
circle(250, 465, 5);
}
I used a photo of me as a baby for this. Once I had the two spirals of hearts running, I added the icons to make it look like an instagram post. When you click, the size of the points in the background increases. When the portrait is done running, an Instagram tag shows up where the mouse is with my childhood nickname.
]]>When browsing through the 3-D Computer Graphics Looking Outwards, I found Poppy’s post about Jennifer Steinkamp’s digital animation “Womb” very interesting. I was initially intrigued by how she wrote about the piece being centered around femininity. I found my peer’s assessment about how the artist’s sensibilities manifesting in the piece to make a meaningful analogy with her work very insightful.
I admire the way the artist uses bright “Fruit Ninja” style visuals to create a thought-provoking piece. Steinkamp describes this piece as a way of showing how a womb is a place of transformation that “grows and stretches outward to exercise agency.” With this piece, the viewer acts as the form of agency as the piece’s movement mirrors the viewer’s movement. I agree with my peer’s assessment that this is an interesting way to represent how we as people take up space.
I learned that the wind sound used is taken from the Wizard of Oz tornado scene, which I thought was an interesting choice as it’s unrelated to the subject matter of the piece. I also learned that Steinkamp tailors each of her pieces depending on the space in which she shows, which I thought was very impressive.
]]>Giorgia Lupi is an information designer, partner at Pentagram, co-founder of Accurat, and co-author of two books. She got her master’s degree in Architecture and is based out of Milan and New York. Her work is featured at the MoMA, Cooper Hewitt, and Smithsonian. She describes herself as a data humanizer, she humanizes data through the story behind the data. Her body of work usesdata to visualize aspects of life that we ‘don’t usually associate with numbers.’ Her work ranges from hand-drawn data visualizations to data driven fashion collections to large-scale computer graphics for big names like SNL and IBM.
I admire how Lupi uses data to better understand human nature because she helps her audience empathize with others. For example, in the project of hers I admire most, Bruises she uses her friend’s daughter’s clinical data to illustrate both the factual and emotional aspect of the experience. Lupi’s presentation strategy is a conversational tone and a ton of visual aids. This is effective because it doesn’t feel dry, she tells a story and uses humor to engage her audience. I can definitely learn from the way she frames the story of her art to help her audience relate more.
var r = 0; //red color variable
var a = 0; //radius of circle a (inner circle) for parametric function
var b = 0; //radius of circle b (fixed circle) for parametric function
var h = 0; //distance from center of inner circle
var theta = 0; //angle variable
function setup() {
createCanvas(480, 480);
background(220);
}
function draw() {
//changing red level of background
r = map(mouseX, 0, 480, 0, 255);
background(r, 200, 200);
//creates 9 Hypotrochoid curves
for (var x = 0; x <= 400; x += 160) {
for (var y = 0; y <= 400; y += 160) {
push();
translate(x+80, y+80);
drawHypotrochoid();
pop();
}
}
//creates 16 Hypotrochoid Evolute curves
for (var x = 0; x <= 480; x += 160) {
for (var y = 0; y <= 480; y += 160) {
push();
translate(x, y);
drawEvolute();
pop();
}
}
}
function drawHypotrochoid() {
//curve based on the Hypotrochoid equation
strokeWeight(0.5);
stroke(255);
noFill();
beginShape();
a = map(mouseX, 0, 480, 1, 70);
b = map(mouseY, 0, 480, 1, 5);
h = map(mouseX, 0, 480, 1, 40);
for (var i = 0; i < 2000; i++) {
var x = (a-b)*cos(theta) + h*cos((a-b)/b*theta);
var y = (a-b)*sin(theta) + h*sin((a-b)/b*theta);
var theta = map(i, 0, 360, 0, TWO_PI);
vertex(x, y);
}
endShape();
pop();
}
function drawEvolute() {
//curve based on the Hypotrochoid Evolute equation
strokeWeight(1);
stroke(0, 150, 0);
noFill();
beginShape();
a = 8*map(480-mouseX, 0, 480, 1, 30);
b = 2*map(480-mouseY, 0, 480, 1, 20);
h = 3*map(480-mouseX, 0, 480, 1, 10);
for (var i = 0; i < 4000; i++) {
var x = (a-b)*cos(theta) + h*cos((a-b)/b*theta);
var y = (a-b)*sin(theta) + h*sin((a-b)/b*theta);
var theta = map(i, 0, 480, 0, TWO_PI);
vertex(x, y);
}
endShape();
pop();
}
For this project, I tried out a few of the equations from the reference and liked the look of the Hypotrochoid the best. Once I had the Hypotrochoid curve working I want to add some visual interest by replicating them with a loop. Once that was done, I added another curve, the Hypotrochoid Evolute and replicated that with a loop too. After the curves were all in place, I added the changing background. The biggest challenge was understanding how changing the values of variables in the equations effected the curve but once I was able to get that it was fun to mess around with!
]]>“Flight Patterns” was developed by Aaron Koblin, Scott Hessels, and Gabriel Dunne as part of a series of experiments for the project “Celestial Mechanics” initially created in August 2005. The artists parsed and plotted data using the Processing Programming Environment. The frames were then composited on Adobe After Effects and Maya.
I admire the artist’s ability to convey so much information through the different variations and avoids overcrowding the piece. Each element provides a new detail, the brightness increases as flight density increases, color represents type of aircrafts and altitude. I also admire the way he is able to create visual interest out of mundane data; each flight pattern looks like a mini firework.
The creator’s artistic sensibilities manifest in the final form through the story the piece tells. In Koblin’s Ted Talk he talks about how collecting data can make us more human and how he humanizes data through his work. For example, with this specific piece, you can see when people depending on their region are the busiest based on how bright that part of the piece is.
]]>