## Final Project

My project was inspired by a silly idea I had for a flip book of my personal failures revolving around the bouncing ball problem from early on in the class. That evolved into slides containing the ball that you had to click or else the game would end. Eventually I figured with all the problems the year had I could make it America and the ball representing the horrible things popping up all over the country. The user has to keep clicking on the ball as it bounces around the map until they win. Every time the map goes off the canvas, the ball gets faster and more red and the background gets darker. The screen will also begin to crack. Encouraging and frightened dialogue will also appear at the bottom and top respectively, and I’ve included instructions and a brief introduction in the console at the start of the game. I wish I had more time to flesh out the theme of the multiple problems of the year and could’ve made multiple minigames rather than just one, or a more involved animation, but after how poorly my proposal turned out I’m very happy with what I have.

``````var slides = []
var threat = 0
var prevent = 0
var incomingX = -100
var incomingY = -100
var incomingSize = 20
var u
var t
var rectY = -200
var flag;
var pic;
var hasDrawn = false
var lineX = []
var lineY= []
var gameStart = false
var hasWritten = false

function makeSlide(sX, sY, sDX, slideTime, ballX, ballY, bounceX, bounceY){
slide = {x: sX, y: sY, dx: sDX, timing: slideTime, drawFunction: drawSlide, stepFunction: slideSlide, extra: drawBall, extraMove: ballMove, extraX: ballX, extraY: ballY, moveX: bounceX, moveY: bounceY}
return slide
}

function drawSlide(){
imageMode(CENTER)
image(pic, this.x, this.y, 350, 350)
}

function slideSlide(){
this.x += this.dx
if(this.x >= 600 || this.x <= -200){
this.dx *= -1
} if (this.x == 600){
this.dx -= 2
} else if (this.x == -200){
this.dx += 2
}
}

function drawBall(){
stroke(0, 0, 0)
fill(256 - threat, (256 -(threat * 13)), 256 -(threat * 13))
circle(constrain(this.extraX, this.x - 155, this.x + 175), constrain(this.extraY, 30, 350), 40)
}

function ballMove(){
this.extraX += this.dx
this.extraX += this.moveX
this.extraY += this.moveY
if (this.extraX >= this.x + 175 || this.extraX <= this.x - 155){
this.moveX *= -1
} if (this.extraY >= 330 || this.extraY <= 30){
this.moveY *= -1
}
if (mouseIsPressed & dist(mouseX, mouseY, this.extraX, this.extraY) <= 20){
prevent += 1
}
else if (this.x == 600 || this.x == -20){
threat += 1
}
}

}

function setup() {
angleMode(DEGREES)
frameRate(15)
createCanvas(400, 400);``````

## Final Project!

For my final project, I wanted to create a game that presents a picture at the end with hidden images that represent events of 2020. The user is able to click two images to switch the locations of the images, and therefore unscramble the original scrambled image that loads. In order not to pressure the user or make the user create one “right answer”, I chose not to tell the user when the image is “correctly” unscrambled. Therefore, the game acts more like a pressure-free artistic adaptation of an image if they’d like.

sketch
``````// Susie Kim
// Final Project
// susiek@andrew.cmu.edu
// Section A

// set global variables
var imgLinks = [
"https://i.imgur.com/vGhpX7m.jpg", //1
"https://i.imgur.com/bNtGvLH.jpg", //2
"https://i.imgur.com/cWHfsai.jpg", //3
"https://i.imgur.com/hnFyXIy.jpg", //4
"https://i.imgur.com/06xo9FF.jpg", //5
"https://i.imgur.com/FJbeTn2.jpg", //6
"https://i.imgur.com/HZduFcW.jpg", //7
"https://i.imgur.com/fU2goSM.jpg", //8
"https://i.imgur.com/i4BVpfk.jpg", //9
"https://i.imgur.com/dvCAEzm.jpg", //10
"https://i.imgur.com/t7FzJVW.jpg", //11
"https://i.imgur.com/MVcrDnK.jpg", //12
"https://i.imgur.com/QUBppYU.jpg", //13
"https://i.imgur.com/IPIsgqD.jpg", //14
"https://i.imgur.com/Inkq9Nc.jpg", //15
"https://i.imgur.com/FJotQ09.jpg"]; //16

gridRows = 4;
gridCols = 4;
sqSize = 100;

images = [];
puzzles = [];
ids = [];
shuffledIds = [];

clickedImgs = [];
numClicks = 0;

// preload image links into images array
for (var i=0; i < 16; i++) {
}
}

function setup() {
createCanvas(500, 500);
background(145, 168, 209);

// write instructions text ontop and bottom
fill(255);
text('complete the puzzle to see the image :)', 150, 35);
text('click 2 pictures to switch their location!', 150, 475);

push();

// write instructions text on left and right
translate(250, 250);
text('2020 in review', -35, 225);

text('2020 in review', -35, 225);
pop();

// create a set of shuffled ids:
for (var i = 0; i < 16; i++) {
ids[i] = i;
}
shuffledIds = shuffle(ids);

// make 16 objects with object properties
for (var i = 0; i < gridRows; i++) {
for (var j = 0; j < gridCols; j++) {
puzzles[j+i*4] = makePuzzle(50+j*100, 50+i*100, shuffledIds[j+i*4], j+i*4);
}
}
}

function draw() {
// draw the grid of shuffled images
for (var i = 0; i < gridRows; i++) {
for (var j = 0; j < gridCols; j++) {
puzzles[j+i*4].display();
}
}
}

// create an object that holds the images' properties
function makePuzzle(xlocation, ylocation, idNum, idNum2) {
var makeImg = { x1: xlocation,
y1: ylocation,
shuffId: idNum,
origId: idNum2,
display: makeImage }
return makeImg;
}

// function that creates the image
function makeImage() {
image(images[this.shuffId], this.x1, this.y1, 100, 100);
}

// if mouse is clicked on two images, switch them
function mouseClicked() {
for (var i = 0; i < 16; i++) {
if (mouseX > puzzles[i].x1 & mouseX < puzzles[i].x1+100 && // boundaries of any image i
mouseY > puzzles[i].y1 && mouseY < puzzles[i].y1+100) {
clickedImgs.push(puzzles[i].origId); // push original Id value of clicked image into clickedImgs array
numClicks += 1;
}
}
// if 2 images are clicked, swap, and reset clicknum to 0
if (numClicks == 2) {
swapImages();
numClicks = 0;
}
}

// function that swaps the two images
function swapImages() {
// store the x and y values in a temporary variable
var tempX = puzzles[clickedImgs[0]].x1;
var tempY = puzzles[clickedImgs[0]].y1

// switch the x and y values
puzzles[clickedImgs[0]].x1 = puzzles[clickedImgs[1]].x1;
puzzles[clickedImgs[0]].y1 = puzzles[clickedImgs[1]].y1;

puzzles[clickedImgs[1]].x1 = tempX;
puzzles[clickedImgs[1]].y1 = tempY;

// clear the clickedImgs array
clickedImgs.pop();
clickedImgs.pop();
}``````

Some examples of imagery I used was a basketball for Kobe Bryant’s death, a fire printed bag for the California and Australia wildfires, a tiger poster for Tiger King, and an Oscar for Parasite winning Best Picture.

## Final Project

hcFinal
``````var picfiles = ["S0UUF6k.png", "QRebAPt.png", "kPzEtew.png", "GDfUrs9.png",
"RdaK8Db.png", "rJua0RK.png", "OFcSHV3.png", "MOsS3A0.png", "gqBXY2d.png",
"O6M0opw.png", "dMPlHtH.png", "KQPXYro.png", "0k3Synd.png", "lXtNJ7L.png",
"046RWzZ.png", "gybarRF.png"];
var soundfiles = ["a.mp3", "b.mp3", "c.mp3", "d.mp3", "e.mp3", "f.mp3","g.mp3",
"h.mp3", "i.mp3", "j.mp3", "k.mp3", "l.mp3", "m.mp3", "n.mp3", "o.mp3", "p.mp3"]; //Will add more sound files later
var pics = [];
var sounds = [];
var channelobj = [];
var oldindex = -1;
var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"];
var colors = [];
var titles = ["Australia fire", "BLM protest", "Chadwick Bosewman death", "Death of Chadwick Boseman", "Explosion in Beirut",
"Florida man saves his dog from an alligator", "Gas explosion in Nigeria", "Harvey Weinstein convicted",
"Impeachment trial of Trump", "Joe Biden wins", "Kobe Bryant death", "Locust swarm", "Murder hornets in US",
"NASA's Mars 2020", "Olympics postponed", "Presidential election"]
var relkey=-1;

//sound files
for (var i = 0; i < soundfiles.length; i++){
sounds[i] = createAudio(concat ("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/12/", soundfiles[i])); //stop() doesn't work with loadSound
//image files
pics[i] = loadImage(concat ("https://i.imgur.com/", picfiles[i]));
}
}

function makeChannel(letter, letterColor){ //Using object to combine letters and their color
ch = {l: letter, lc: letterColor
}
return ch;
}

function setup(){
createCanvas(500, 500);
rectMode(CENTER);
imageMode(CENTER);
//Giving all letters the same gray color in the beginning
for (var i = 0; i < letters.length; i++){
channelobj[i] = makeChannel(letters[i], color(222, 217, 209));
}
}

function draw(){
background(240, 255, 254);
TV();
drawTitle(relkey);
drawText(relkey);
}

function drawText(nSelect){
if (nSelect > -1 & nSelect < letters.length){ //Making selected letter to turn black
channelobj[nSelect].lc = color(0);
}
for (var i = 0; i < channelobj.length; i++){ //Giving characteristics and placement to the letters
textAlign(CENTER);
fill(channelobj[i].lc);
textSize(25);
text(channelobj[i].l, 20 * i + 100, 450);
}
if (nSelect > -1 & nSelect < letters.length){ //Making the letters to turn back to gray
channelobj[nSelect].lc = color(222, 217, 209);
}
}

function drawTitle(nSelect){
noStroke();
fill(240, 255, 254);
rect(250, 60, 500, 120); //drawing rect to cover previous titles
if (nSelect > -1 & nSelect < titles.length){
textAlign(CENTER);
fill(0);
textSize(25);
text(titles[nSelect], 250, 90);
}
}

function keyPressed(){
loop();
relkey = keyCode - 65; //65 = 'a' keycode, found on p5js.org
if (relkey > channelobj.length - 1 || relkey < 0){ //Checking the pressed key is in between a~p
return; //returning any key that is not a~p
}

for(var i = 0; i < sounds.length; i++){ //Stopping the audio from previous channel (isPlaying found on p5js.org)
sounds[i].stop(0);
}
sounds[relkey].play(); //Calling the correct audio
started = true;
}

function TV(){
//Drawing TV
stroke(200);
fill(168, 237, 170);
rect(250, 270, 370, 270, 35);
fill(209, 196, 186);
circle(390, 200, 30);
circle(390, 250, 30);
for (var i = 300; i < 360; i += 10){
rect(390, i, 20, 5);
}
fill(100);
if (relkey > - 1 & relkey < channelobj.length ) {
image(pics[relkey], 220, 270); //Calling the correct image
} else {
rect(220, 270, 260, 220);
for(var i = 0; i < sounds.length; i++){ //Stopping the audio from previous channel
sounds[i].stop(0);
}
}
}

fill(255);
push();
translate(220, 270);
for (var i = 0; i < 6; i++){
push();
rotate(radians(frameCount + 60 * i));
ellipse(30, 0, 20, 10);
pop();
}
pop();
}``````

For this project, I wanted to create a television that shows the events that happened in 2020. I was inspired to work on this project since so many people talked about how they will never speak of 2020 in the future. I thought it would be fun to create a program that sums up this year and show it to people in the future to bring their memories back.

I tried to find a somewhat cute way to show the events since a lot of them are disturbing news. It felt like 2020 was a disastrous year and it was hard to pin down just one main event to show. So I decided to find a way to show all the “key” events of 2020.

You can watch the channels by pressing the keyboard from “a” to “p.” If you press any keyboard that is not one of those alphabets, the television will stop playing.

## Final Project

This is a fun little animated/interactive sequence on the death of the theater industry because of COVID. It is mostly cut off because of wordpress!!

sketch
``````var clouds = [];
var grassLeftOn = true
var grassRightOn = true
var tiktok; //image of the tiktok logo that emerges from the death of the
//theater industry
var rat; //image of the ratatouille musical that is saving the theater
//industry right now
var angle = 0 //to rotate the images of tiktok and ratatouille

}

function setup() {
createCanvas(1500, 700);
background(220);
frameRate(10);
for (var i = 0; i < 5; i++) {
clouds[i] = new Object();
clouds[i].x = random(1500);
clouds[i].y = random(300);
clouds[i].size = random(100);
clouds[i].dx = random(5);
}
}

function draw() {
background(82, 0, 124);
strokeWeight(1);
fill(233, 228, 236, 190);
circle(750, 110, 200); //this is the moon
textSize(15);
textAlign(CENTER, CENTER);
fill(255, 247, 0);
text('Click Any Grave', 750, 80);
text('But Beware', 750, 100);
text('Click The Center Grave Twice', 750, 120);
text('If You Dare', 750, 140);
fill(6, 117, 14);
rect(0, 400, 1500, 300); //this is the horizon
fill(48, 186, 57);
beginShape(); //this is the path leading to the "death of theater" grave
vertex(620, 700);
vertex(620, 700);
vertex(690, 450);
vertex(810, 450);
vertex(880, 700);
vertex(620, 700);
vertex(620, 700);
endShape();
strokeWeight(3);
gates(); //for the gates in the background
//clouds moving across the screen
for (var i = 0; i < 5; i++) {
draw_clouds(clouds[i]);
clouds[i].x += clouds[i].dx;
if (clouds[i].x > 1750) {
clouds[i].x = -250
}
}
//populate the landscape with graves
strokeWeight(2);
stroke(0);
graves(690, 450, 240, 120); //center grave
graves(480, 680, 260, 180); //left front
grassLeft(472, 681, 30, 40);
grassRight(585, 681, 40, 30);
graves(900, 680, 190, 210); //right front
grassLeft(892, 681, 20, 70);
grassRight(990, 681, 20, 40);
graves(160, 550, 80, 120); //left mid
grassLeft(152, 551, 10, 90);
grassRight(195, 551, 10, 90);
graves(390, 470, 70, 20); //left back
grassLeft(386, 471, 5, 10);
grassRight(420, 471, 10, 5);
graves(1080, 500, 120, 80); //right mid
grassLeft(1072, 501, 20, 50);
grassRight(1130, 501, 20, 35);
graves(1420, 410, 60, 80); //right back
grassLeft(1412, 411, 10, 30);
grassRight(1448, 411, 10, 30);
if (frameCount % 10 == 0) { //grass moves back and forth like the wind is blowing through it
if (grassLeftOn == true) {
grassLeftOn = false
} else {
grassLeftOn = true
}
if (grassRightOn == true) {
grassRightOn = false
} else {
grassRightOn = true
}
}
if (mouseIsPressed) {
if (mouseX > 690 & mouseX < 810 && mouseY > 330 && mouseY < 450) {
clickCenterGrave();
}
if (mouseX > 480 & mouseX < 610 && mouseY > 500 && mouseY < 680) {
clickLeftFrontGrave();
}
if (mouseX > 900 & mouseX < 980 && mouseY > 470 && mouseY < 680) {
clickRightFrontGrave();
}
if (mouseX > 160 & mouseX < 200 && mouseY > 430 && mouseY < 550) {
clickLeftMidGrave();
}
if (mouseX > 390 & mouseX < 425 && mouseY > 450 && mouseY < 470) {
clickLeftBackGrave();
}
if (mouseX > 1080 & mouseX < 1140 && mouseY > 420 && mouseY < 500) {
clickRightMidGrave();
}
if (mouseX > 1420 & mouseX < 1450 && mouseY > 330 && mouseY < 410) {
clickRightBackGrave();
}
}
}

function mouseReleased() {
if (mouseX > 690 & mouseX < 810 && mouseY > 330 && mouseY < 450) {
finalSequence(); //launches the final sequence after mouseIsPressed is released for the center grave
}
}

function draw_clouds(cl) {
noStroke();
fill(231, 250, 253);
circle(cl.x, cl.y, cl.size);
circle(cl.x - cl.size/4, cl.y, cl.size - (cl.size/5));
circle(cl.x + cl.size/4, cl.y, cl.size - (cl.size/5));
circle(cl.x - cl.size/2, cl.y, cl.size - (cl.size/4));
circle(cl.x + cl.size/2, cl.y, cl.size - (cl.size/4));
}

function gates() {
line(0, 250, 700, 250);
line(800, 250, 1500, 250);
for (var x = 0; x < 710; x += 10) {
line(x, 250, x, 400);
}
for (var x = 800; x < 1510; x += 10) {
line(x, 250, x, 400);
}
}

function graves(x, y, hsize, vsize) {
fill(165);
beginShape();
vertex(x, y);
vertex(x, y);
vertex(x, y - vsize +  vsize/6);
curveVertex(x + hsize/8, y - vsize);
curveVertex(x + 3*hsize/8, y - vsize);
vertex(x + hsize/2, y - vsize + vsize/6);
vertex(x + hsize/2, y);
vertex(x + hsize/2, y);
endShape();
}

function grassLeft(x, y, hsize, vsize) {
fill(12, 182, 0);
beginShape();
curveVertex(x, y);
curveVertex(x, y);
curveVertex(x + hsize/4, y - vsize/2);
if (grassLeftOn == true) {
curveVertex(x, y - vsize);
} else {
curveVertex(x + hsize, y - vsize);
}
curveVertex(x + 3*hsize/4, y - vsize/2);
curveVertex(x + hsize, y);
curveVertex(x + hsize, y);
endShape();
}

function grassRight(x, y, hsize, vsize) {
fill(12, 182, 0);
beginShape();
curveVertex(x, y);
curveVertex(x, y);
curveVertex(x + hsize/4, y - vsize/2);
if (grassRightOn == true) {
curveVertex(x + hsize, y - vsize);
} else {
curveVertex(x, y - vsize);
}
curveVertex(x + 3*hsize/4, y - vsize/2);
curveVertex(x + hsize, y);
curveVertex(x + hsize, y);
endShape();
}

function clickCenterGrave() { //text that appears on the screen if you click and hold the center grave
fill(165);
rect(0, 0, 1500, 700);
textSize(100);
textAlign(CENTER, CENTER);
fill(0);
text('Here Lies The Theater Industry', 750, 300);
textSize(70);
text('May She Be Reborn Into Something Better', 750, 400);
}

function clickLeftFrontGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(90);
textAlign(CENTER, CENTER);
fill(0);
text('RIP Comm. Herschel Brawdweigh', 750, 300); //commercial broadway
textSize(130);
text('Father to Tony', 750, 440); //the tony's
}

function clickRightFrontGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(90);
textAlign(CENTER, CENTER);
fill(0);
text('Miss Nadia Marika', 750, 300); //miss not america
textSize(100);
text('Outside Of US, There Is Nothing', 750, 440); //outside of us/the U.S.
}

function clickLeftMidGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(70);
textAlign(CENTER, CENTER);
fill(0);
text('Together Forever: Dez Ein and Prof. Duckshun', 750, 300); //design and production
textSize(130);
text('They Were the Best of Us', 750, 440);
}

function clickLeftBackGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(90);
textAlign(CENTER, CENTER);
fill(0);
text('Newt Hamster', 750, 300); //new amsterdam theater
textSize(130);
text('A Dam Beloved Pet', 750, 440);
}

function clickRightMidGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(90);
textAlign(CENTER, CENTER);
fill(0);
text('To Brooks Atkinson', 750, 300); //brooks atkinson was a famous theater critic
textSize(130);
text('Critics Die Too', 750, 440);
}

function clickRightBackGrave() {
fill(165);
rect(0, 0, 1500, 700);
textSize(90);
textAlign(CENTER, CENTER);
fill(0);
text('Call Me By Your Name', 750, 300); //theater saying "call me film" because all we have is filmed productions heehee I'm hilarious
textSize(130);
text('Film Is All We Have Now', 750, 440);
}

function finalSequence() { //when the mouse is first released, all animated movement stops
//when the mouse is clicked again and released, the center grave cracks
//the tiktok logo, a picture of ratatouille appears, and a title appears
//this is because the ratatouille musical is the only exciting thing happening in theater right now
//if the user wants to view the other graves after this one, they have to restart the program
//but if they keep clicking, the tiktok/ratatouille images will rotate!
noLoop();
strokeWeight(3);
line(750, 330, 730, 350);
line(730, 350, 770, 390);
line(770, 390, 730, 430);
line(730, 430, 770, 470);
line(770, 470, 730, 520);
line(730, 520, 770, 580);
line(770, 580, 730, 640);
line(730, 640, 770, 700);
push();
translate(325, 350);
image(tiktok, -175, -200, 350, 400);
pop();
push();
translate(1175, 350);
image(rat, -175, -200, 350, 400);
pop();
angle += 5
fill(255, 247, 0);
textSize(40);
textAlign(CENTER, CENTER);
text('"Playbill Announces a Concert Presentation of Ratatouille: The Tiktok Musical"', 750, 30);
}``````

## Final Project – social distance

sketch

I created a interactive game about Covid-19. When the program runs, it first gives the instruction of the game for the first few seconds, You have to click on the heads of the humans to remove them, so that they keep social distance. If you successfully keep the number of the people under 4, you succeed. If you fail to do so and there are more than 12 people, game over. I was inspired by how the social distance is crucial to keep us safe during this time of pandemic. We just have to keep ourselves not too crammed in one place! I wish I could add more interactive/intuitive features including click to start or click to restart the game.

``````//Jae Son , Section C

var humans = [];

function setup() {
createCanvas(500, 400);
rectMode(CENTER);
frameRate(20);
}

function draw() {
background(210,237,178);

for (var i = 0; i < humans.length; i++){
var human = humans[i];
humans[i].display();
}
//game instruction in the beginning
if (frameCount <80) {
noStroke();
fill(152,183,108);
rect(250,200,300,200);
fill(255);
textSize(20);
textStyle(BOLD);
text('click the head and',140,180);
text('remove the humans to',140,200);
text('keep the social distance',140,220);
}
//game starts after the instruction
if (frameCount > 80 & frameCount % 10 == 0){
var newHuman = createHuman(random(25,476),random(10,278),0,0);
humans.push(newHuman);
}
//if there is more than 12 people, game over
if (humans.length > 12) {
fill(242,158,158);
rect(250,200,350,250);
fill(255);
textSize(20);
textStyle(BOLD);
text('No one bothered to keep',130,140);
text('the social distance',130,160);
text('and Now we are at the',130,180);
text('highest risk of COVID 19.',130,200);
text('Try better!',130,240);
frameRate(0);
}
//if there is less than 4 people, game clear
if (humans.length < 4 & frameCount > 200){
fill(157,209,244);
rect(250,200,300,250);
fill(255);
textSize(20);
textStyle(BOLD);
text('Everyone kept the',140,140);
text('social distance and',140,160);
text('and we are at',140,180);
text('lower risk of COVID 19.',140,200);
text('Good job!',140,240);
frameRate(0);
}
}

//humans

//creating Human objects and drawing them
function createHuman(humanx,humany,humandx,humandy){
var human = {x: humanx, y: humany,
dx: humandx, dy: humandy,
display: drawHuman,
humancolor: color(random(220,255),random(80,100),random(100,200))
}
return human;
}

function drawHuman(){
noStroke();
fill(this.humancolor);
push();
ellipse(this.x,this.y,15,15);
rect(this.x,this.y+22,16,27);
rect(this.x-12,this.y+22,4,22);
rect(this.x+12,this.y+22,4,22);
rect(this.x-3,this.y+52,5,33);
rect(this.x+3,this.y+52,5,33);
pop();
}

//remove humans when their head is clicked
function mousePressed() {
for (var i = humans.length - 1; i >= 0; i--) {
if (dist(humans[i].x, humans[i].y, mouseX, mouseY) < 20) {
humans.splice(i, 1);
}
}
}

``````

## Final Project – Interactive Pandemic Visualizer

sketch
``````/*
* Eric Zhao
* ezhao2
* 15-104D
* Final Project: Pandemic Simulation
*/

var p;
var noiseStep = 0.005;
var noiseParam = 0;
var particles = []; //all particles
var numParticles = 50;
var infectedList = []; //all the particles that are infected
var generation = 0; //what "round" of infection the dots are on
var colorList = []; //list of colors to mark the generation of infection
var paused = false; //is the program paused?
var numCols = 8; //number of dots per row (color picker)
var menuMode = 0; //shows controls or visualizations
var masksOn = false; //are the particles wearing masks
var filterCol = 0; //color
var filterState = false; //is the program filtering dots?
var masksOn = false; //are the dots wearing masks?
var sketchState = 0; //affects if title screen is displayed

function setup() {
//makes array of particles and infects the first one
createCanvas(400, 600);
background(100);
colorMode(HSB);
for(var i = 0; i < numParticles; i++){
p = makeParticle(random(0, width), random(0, height), 3, 3,
random(0, 100), i);
particles.push(p);
}
var startColor = color(0, 100, 100);
colorList.push(startColor);

particles[0].infectedBy = 0;
particles[0].size = 25;
particles[0].infectColor = colorList[0];
infectedList.push(particles[0]);

}

function draw(){
stroke(100);
background(50, 20, 20);
fill(100);
for(var i = 0; i < numParticles; i++){
if(particles[i].infectedBy != -1){
drawConnections(particles[i]);
}
}
for(var i = 0; i < numParticles; i++){
particles[i].draw();
if(paused == false){
particles[i].step();
}
}
if(paused == false){
noiseParam+=noiseStep;
}
drawUI();
}

function makeParticle(px, py, dpx, dpy, noiseOffset, index){
p = {x: px, y: py, dx: dpx, dy: dpy,
infectedBy: -1, //if infected, which dot infected it?
ID: index, //the dot's position in the original array
infectColor: color(0, 0, 100), //color of the dot
size: 10, //size of the dot
offset: noiseOffset,
step: stepParticle,
draw: drawParticle};
return p;
}

function stepParticle(){
//moves particle based on Perlin noise

this.x = width * map(noise(noiseParam + this.offset), 0, 1, -0.4, 1.4);
this.y = width * map(noise(noiseParam + this.offset + 5), 0, 1, -0.4, 1.4);
}

function drawParticle(){
fill(255);
push();
noStroke();
if(this.infectedBy > -1){
fill(this.infectColor);
}
//show dot only if not filtering or if it matches filter color
if(filterState == true){
var tempCLR = getRGB(this.infectColor);
if(compareColors(tempCLR, filterCol) == false){
noFill();
}
}
circle(this.x, this.y, this.size);
pop();
}

function drawConnections(infectedP){
//draws a line between a dot and its infector
push();
var ind = infectedP.infectedBy;
if(infectedP.infectedBy > -1){
var tempCLR = particles[ind].infectColor;
strokeWeight(1);
stroke(tempCLR);
}
//show line only if it matches the filter color
if(filterState == true){
var infectedRGB = getRGB(tempCLR);
if(compareColors(tempCLR, filterCol) == false){
noStroke();
}
}
line(infectedP.x, infectedP.y, particles[ind].x, particles[ind].y);
pop();
}

function infection(population, infected){
//make empty array, push newly infected particles here

//if particles were infected, generate a new fill color
//for them

//adjust size of infected particles
var base = infected.length;
var newCases = [];
print("Previous number: "+infected.length);

//the basic logic: for all infected particles, check
//if any non-infected particles are nearby. If so,
//infect the particle and push it to an empty array.
//add this array to the whole list of infected particles
//at the end.
for(var i = 0; i < infected.length; i++){
for(var j = 0; j < numParticles; j++){
if(dist(population[j].x, population[j].y,
infected[i].x, infected[i].y) < 25
& population[j].infectedBy == -1){
if(random(0,1) > 0.66){
population[j].infectedBy = infected[i].ID;
newCases.push(population[j]);
}
} else {
population[j].infectedBy = infected[i].ID;
newCases.push(population[j]);
}
}
}
}

if(newCases.length > 0) {
for(var i = 0; i < newCases.length; i++){
infected.push(newCases[i]);
}
generation++;
var newC = color(random(360), random(25, 100), 100);
colorList.push(newC);
print(infected.length);
print(colorList.length);
for(i = 0; i < (infected.length-base); i++){
//makes particle size 90 percent of the one it was infected by
infected[base+i].size =
0.9*(particles[infected[base+i].infectedBy].size);
//changes color to a new random fill (per generation)
infected[base+i].infectColor = colorList[generation]; //
}
}
print("Number infected: " + infected.length);
print("Generation: "+ generation);
print(colorList.length);
print("__________h_______");
}

function mousePressed(){
if(sketchState == 0){
sketchState = 1;
} else {
if(mouseY < width){
infection(particles, infectedList);
} else if(mouseY >= width & mouseY <= height){
filterStatus(get(mouseX, mouseY));
}
}
}

function keyTyped(){
if(key === 'p'){
//pause function that freezes movement but allows infection
pauseMove();
}
if(key === 'r'){
//Resets dot states but not entire sketch
resetSketch();
}
if(key === 'h'){
//switches menu between guide and data visualization
print('data');
} else {
print('help');
}
}
if(key === 'm'){
} else{
}
}
}

function titleScreen(){
push();
translate(25, 75);
stroke(100);
fill(50, 5, 100, 0.9);
textSize(14);
var rectW = width - 50;
var rectH = 0.48*height;
var backgroundTxt = "This is a simple simulation of a viral outbreak \
such as COVID-19 modeled with a number of colored dots.";
var inst_1 = "1) Each time you click, all infected (colored) dots \
will infect those nearby."
var inst_2 = "2) Connections between the infector and newly infected \
dot are shown."
var inst_3 = "3) Make the dots wear masks by pressing [ W ]."
var inst_4 = "4) Filter infected dots by pressing [ H ]."
var inst_5 = "5) Reset all dots with [ R ]."
var inst_6 = "(click anywhere to hide)"

rect(0, 0, rectW, rectH, 10);
fill(0);
textSize(18);
textStyle(BOLD);
text("Visualizing a Pandemic", 20, 30);
textSize(14);
text("How to Use:", 20, 105);
textSize(12);
textStyle(NORMAL);
text(backgroundTxt, 20, 50, 300, 150);
text(inst_1, 20, 120, 300, 150);
text(inst_2, 20, 160, 300, 150);
text(inst_3, 20, 200, 300, 150);
text(inst_4, 20, 225, 300, 150);
text(inst_5, 20, 260);
text(inst_6, 215, 28);
stroke(0);
line(20, 40, rectW-20, 40);
pop();
}

function drawUI(){
push();
if(sketchState == 0)
titleScreen();
translate(25, width);
fill(50, 20, 25, 0.75);
textSize(14);
var rectW = width - 50;
var rectH = (height-width)-25;
rect(0, 0, rectW, rectH, 10);
noStroke();
fill(100);
textSize(14);
textStyle(BOLD);

fill(120, 72, 90);
text("Masks ON", 275, -10);
} else{
fill(0, 72, 90);
text("Masks OFF", 275, -10);
}

fill(100);
displayHelp();
} else{
displayData();
}
pop();
push();
if(paused){
rect(width-50, 25, 8, 25);
rect(width-34, 25, 8, 25);
} else {
triangle(width-50, 25, width-50, 50, width-25, 37.5);
}
}

function displayHelp(){
textSize(14);
textStyle(BOLD);
text("Guide", 20, 30);
textStyle(NORMAL);
textSize(12);
text("( Press [ H ] to switch to filters )", 65, 30);
text("[ P ] : Freeze / Unfreeze dots", 20, 100);
text("[ R ] : Disinfect all dots (except Patient Zero)", 20, 80);
text("[ CLICK ] to infect nearby dots", 20, 60);
text("[ M ] : Toggle masks ON / OFF", 20, 120);
text("[ H ] : Show / Hide controls", 20, 140);
stroke(100);
}

function displayData(){
noStroke();
fill(100);
textSize(14);
textStyle(BOLD);
text("Filter Data", 20, 30);
textStyle(NORMAL);
textSize(12);
if(filterState){
text("( CLICK away from squares to show all )", 90, 30);
} else{
text("( CLICK to isolate )", 90, 30);
}
drawPalette();
}

function resetSketch(){
//code modified from setup();
for(var i = 0; i < numParticles; i++){
particles[i].infectedBy = -1;
particles[i].infectColor = color(0, 0, 100);
particles[i].size = 10;
}
//wipes all modifier arrays
filterState = false;
generation = 0;
infectedList = [];
colorList = [];
var startColor = color(0, 100, 100);
colorList.push(startColor);

//reinfects first dot
particles[0].infectedBy = 0;
particles[0].size = 25;
particles[0].infectColor = colorList[0];
infectedList.push(particles[0]);
}

function pauseMove(){
if(paused === true){
paused = false;
print('resumed');
} else {
paused = true;
print('paused');
}
}

function drawPalette() {
//on visualization UI, draw color palette to filter dots
translate(20, 50);
var count = 0;
numRows = ceil(colorList.length / numCols);
for(var i = 0; i < numRows; i++) {
for(var j = 0; j < numCols; j++) {
if(count < colorList.length) {
fill(colorList[(i * 6) + j]);
drawColor(40 * (j), 40*i, 30);
count++;
}
}
}
}

function drawColor(x, y, rSize) {
rect(x, y, rSize, rSize, 0.125*rSize);
}

function filterStatus(currentColor){
//reads color of cursor location, enables filtering
//if the mouse is over a colored square
for(var i = 0; i < colorList.length; i++){
print("Infected Color "+i);
var infectRGB = getRGB(colorList[i]);
var cursorRGB = getRGB(currentColor);
print("infected color: " + infectRGB);
print("cursor color: " + cursorRGB);

if(compareColors(infectRGB, cursorRGB) == true){
filterCol = cursorRGB;
filterState = true;
return;
}
}
}
filterState = false;
}

function getRGB(inputColor){
//converts a color into RGB
push();
sampledColor = inputColor;
colorMode(RGB, 255, 255, 255, 1);
var r = red(sampledColor);
var g = green(sampledColor);
var b = blue(sampledColor);
sampledColor = color(r, g, b);
pop();
return sampledColor;
}

function compareColors(color1, color2){
//approximates two colors and checks if they are identical
var r1 = round(red(color1));
var g1 = round(green(color1));
var b1 = round(blue(color1));
var r2 = round(red(color2));
var g2 = round(green(color2));
var b2 = round(blue(color2));

if(r1 == r2 & g1 == g2 && b1 == b2){
return true;
}

return false;

}
``````

When quarantines first started being imposed, I found Youtube channels dedicated to data visualization and education answered all my questions about the COVID-19 pandemic and engaged me to learn further.

Inspired by channels like Primer and 3Blue1Brown, I made an interactive simulation / visualization of a pandemic. Since I had been curious about contact tracing for a while but never understood the concept, I decided to use this opportunity to learn more about it and make it a core feature in my project.

In my visualizer, a population of dots are wandering around the screen. Clicking will cause all infected dots to infect nearby ones. Colored, larger dots have been infected. Additionally, you can see which dot infected which other dot through connecting lines. Since this rough form of contact tracing still gets messy, you can also filter the dots by color (or “generation” of infection) to find “super-spreader” dots.

A good chunk of my time was spent making sure all the interactions worked together without any errors or slowdowns. With more time, I would try mimicking real-life contact tracing more closely through recursion and add animations to the dots.

Below is a short demo of my project demonstrating the difference that having masks on makes on the speed of infection.

## Final Proj: Quarantine Baking Simulator

sketch
``````//iris yip
//15-104
//deliverable week 15
//final project

var page = 1; //set up a bunch of different "scenes"
let spatula;

function setup() {
createCanvas(500, 500);

}

//spatula

//knife

}

function draw() { //scenes

//page 1
if (page == 1) {
image(img1, 0, 0);
}

//page 2
else if (page == 2) {
image(img2,0,0);
}

//page 3
else if (page == 3) {
image(img3,0,0);
}

//page 4
else if (page == 4){
image(img4,0,0);
}

//page 5
else if(page ==5){
image(img5,0,0);

image(spatula1,mouseX,mouseY);
}

//page 6
else if(page ==6){
image(img6,0,0);
}

else if(page ==7){
image(day1,0,0);
}

else if(page ==8){
image(day3,0,0);
}

else if(page ==9){
image(day4,0,0);
}

else if(page ==10){
image(day6,0,0);
}

else if(page ==11){
image(day7,0,0);
}

else if(page ==12){
image(day8,0,0);
}

else if(page ==13){
image(img7,0,0);
}

else if(page ==14){
image(img8,0,0);

image(knife1,mouseX,mouseY);
}

else if (page == 20) {
image(die,0,0);
}
}

function mousePressed() {
// PAGE 1 COMMANDS
if (page == 1) {
if (mouseX > 90 & mouseX < 300 && mouseY > 220 && mouseY < 400) {
page = 2; //proceed forwards into the game
}
else if (mouseX > 300 & mouseX < 400 && mouseY > 350 && mouseY < 400) {
page = 1; //stays the same
}
}

//PAGE 3 COMMANDS
if (page ==3) {
if(mouseX > 350 & mouseY > 200){
page = 4; //proceed forward
}
}
//page 4
if (page ==4){
if(mouseX>400 & mouseY> 220){
page = 5;
}
}
//page 5
if (page ==5){
if(mouseX>150 & mouseX<250 && mouseY>50 && mouseY<250){
page = 6
}
}
//page 6
if(page ==6){
if(mouseX > 400 && mouseX<480 && mouseY> 60 && mouseY<200){
page = 7;
}
}
//page 7
if(page ==7){
if(mouseX>400 & mouseX<480 && mouseY> 60 && mouseY<200){
page = 8;
}
}

if(page ==8){
if(mouseX>400 & mouseY > 60){
page =9;
}
}
if(page ==9){
if(mouseX>50 & mouseX<480 && mouseY>60 && mouseY<300){
page= 13;
}
}
if(page ==13){
if(mouseX>10 & mouseY>10){
page= 14;
}
}
if(page ==14){
if(mouseX>130 & mouseX < 250 && mouseY> 150 && mouseY<200){
page=15;
}
}
}

function keyPressed(){
if(page==2){
if(key=='a'){
page =3; //proceed forwards
}
else if(key != 'a'){
page =20; //dies
}
}

//day1
if(page== 7 & 8 && 9 && 11 && 12){
if(key=='k'){
page = 20
}
else if(key != 'k'){
page =20;
}
}

//last step
if(page ==15){
if(key=='360'){
page = fin
}
else if(key !='360'){
page =20;
}
}
}``````

For my final project, I wanted to make a ‘point-and-click’ adventure style game about baking during quarantine, which would act like a little tutorial adventure of sorts. Growing up, I played a lot of Cooking Mama on the Nintendo, which is where the primary inspiration for this game came from. The instructions for each step are given on the screen, which ranges from clicking on certain parts of the screen to pressing a key and clicking and dragging.

Overall, there were a few parts that I could not get to work (certain scenes being skipped, etc.) but it was really cool to try to replicate the type of mini-game that I would play a lot when I was younger! If I had more time, I’d go back and clean up the code so that it would run more efficiently, and also add in more complex scenes and a grading scale/system rather than the instant death mechanic function.

## Final Project: Self-Care Roulette

I wanted to do an interactive code that gives the user a thing to do during COVID-19. It will generate random tasks that the user can complete each day in light of COVID-19 that allows them to look forward to achieving something each day, despite how sometimes we may just want to stay in bed. These tasks can be give a call to someone you miss, water your plants, or do some skincare. For me, I feel like it has been really easy to get lost in not having a plan for the day or having the motivation to do something for myself since COVID had started. I hope this project can be a daily reminder that self-care can be something small but it is essential to maintain. It is fairly easy to navigate, with a play button to start. Then the user will be prompt to pick one category of activities. There is a next button that will display random activities from the chosen category. The user can choose to refresh to get a new activity or move on and finish the roulette. To restart the game, you just have to refresh the page. Some activities are time based, such as making breakfast or go stargazing.

sketch
``````//Jessie Chen
//D
//Final Project
//Self Care Roulette

//global variables
var title;
var activities = [];
//homepage
var home = true;
//boolean for all categories are not selected
var rel = false;
var soc = false;
var phy = false;
var lng = false;
var qck = false;
//buttons
var play;
var homeButton;
var refresh;
var next;
//cateogies
var relax;
var quick;
var long;
var social;
var physical;

//

var activitiesPage = [];
//long
activitiesPage[0] = "https://i.imgur.com/sNZV5FH.png"; //sewing
activitiesPage[1] = "https://i.imgur.com/82QiPiY.png"; //read
activitiesPage[2] = "https://i.imgur.com/Xld0YcB.png"; //instrument
activitiesPage[3] = "https://i.imgur.com/4AubEbi.png"; //bake
//quick
activitiesPage[4] = "https://i.imgur.com/W1H2LbU.png"; //music
activitiesPage[5] = "https://i.imgur.com/VJqD19E.png"; //draw
activitiesPage[6] = "https://i.imgur.com/3wyiMdR.png"; //breakfast
activitiesPage[7] = "https://i.imgur.com/5wUW5VD.png"; //water plants
//social
activitiesPage[8] = "https://i.imgur.com/jtYM2kP.png"; //call
activitiesPage[9] = "https://i.imgur.com/jrhmmlA.png"; //game
activitiesPage[10] = "https://i.imgur.com/W4TCa01.png"; //facemask
activitiesPage[11] = "https://i.imgur.com/fot757c.png"; //movies

//physical
activitiesPage[12] = "https://i.imgur.com/0zokbRX.png"; //laundry
activitiesPage[13] = "https://i.imgur.com/pO77RCB.png"; //stretch
activitiesPage[14] = "https://i.imgur.com/PpYiJD3.png"; //swim
activitiesPage[15] = "https://i.imgur.com/ew1Hfa5.png"; //run
//relaxing
activitiesPage[16] = "https://i.imgur.com/Yg5lxNt.png" //to do list
activitiesPage[17] = "https://i.imgur.com/TtuDd51.png"; //bath
activitiesPage[18] = "https://i.imgur.com/8bqSaWf.png"; //cloud
activitiesPage[19] = "https://i.imgur.com/2oOvf88.png"; //stars

for (var i = 0; i < activitiesPage.length; i++) {
}
//buttons

//categories
}

function setup() {
createCanvas(600, 450);
}

//set to home page, when home is false, shows categories page
function draw() {
homePage();
if (home == false) {
categories();
}
}

function homePage() {
if (home) {
background(215, 167, 167);
circles();
image(title, 0, 0, width, height);
image(play, 0, 0, width, height);

}
}

//categories page
function categories() {

background(215, 167, 167);
circles();
push();
imageMode(CENTER);

//when relaxing is selected it enlarges
if (!rel) {
image(relax, 150, 230, 200, 80);
} else if (rel) {
image(relax, 150, 230, 300, 130);
}

//when social is selected, it enlarges
if (!soc) {
image(social, 300, 140, 200, 80);
} else if (soc) {
image(social, 300, 140, 300, 130);
}

//when physcial is selected, it enlarges
if (!phy) {
image(physical, 450, 230, 200, 80);
} else if (phy) {
image(physical, 450, 230, 300, 130);
}

//when long is selected, it enlarges
if (!lng) {
image(long, 200, 330, 200, 80);
} else if (lng) {
image(long, 200, 330, 300, 130);
}

//when quick is selected, it enlarges
if (!qck) {
image(quick, 400, 330, 200, 80);
} else if (qck) {
image(quick, 400, 330, 300, 130);
}
pop();

//buttons
image(homeButton, 0, 0, width, height);
image(categoryPage, 0, 0, width, height);
}

//display activities
function activity() {
background(random(150, 200), random(150, 200), random(150, 200));
circles();
var r;

//relaxing activities based on index
if (rel) {
if (hour() > 6 & hour() < 18) { //mornings, excluding the stars
r = int(random([16, 17, 18]));
} else if (hour(0 > 20 & hour() < 4)) { //night time, excluding the clouds
r = int(random([16, 17, 19]));
}
//long activities
} else if (lng) {
r = int(random(0, 4));
//physical activities
} else if (phy) {
r = int(random(12, 16));
//quick activities
} else if (qck) {
if (hour() > 4 & hour() < 12) { //morning including breakfast
r = int(random(4, 8));
} else {
r = int(random([4, 5, 7])); //excluding breakfast past morning
}
//social activities
} else if (soc) {
r = int(random(8, 12));
}

//display image
image(activities[r], 0, 0, width, height);
//buttons
image(next, 0, 0, width, height);
image(refresh, 0, 0, width, height);
noLoop();
}

//thanks for playing
function endPage() {
background(215, 167, 167);
circles();
image(end, 0, 0, width, height);
}

//circles in the background
function circles() {
for (var x = 0; x <= width; x += 20) {
for (var y = 0; y<= height; y += 20) {
noStroke();
fill(242, 220, 203, 120);
ellipse(x, y, 10, 10);
}
}
}

function mousePressed() {
if(mouseX >= 30 & mouseX <= 80 && mouseY >= 30 && mouseY <= 80) {
home = true;
homePage();
}
// play button brings to categories page
if (mouseX >= 220 & mouseX <= 380 && mouseY >= 250 && mouseY <= 320) {
home = false;
categories();
//next button displays activies
} else if(mouseX >= 510 & mouseY >= 370 && mouseX <= 560 && mouseY <= 415) {
activity();
//refresh button displays another activity
} else if(mouseX <= 80 & mouseX >= 25 && mouseY <= 420 && mouseY >= 360) {
activity();
//end button to thanks for playing
} else if (mouseX >= 515 & mouseY >= 15 && mouseX <= 570 && mouseY <= 70) {
endPage();
}

//checks to see if boolean is selected by the user, can click to select and unselect
if (mouseX >= 10 & mouseX <= 230 && mouseY <= 250 && mouseY >= 210) {
rel = !rel;
} else if(mouseX >= 230 & mouseY >= 125 && mouseX <= 360 && mouseY <= 150) {
soc = !soc;
} else if(mouseX >= 375 & mouseY >= 210 && mouseX <= 530 && mouseY <= 245) {
phy = !phy;
} else if(mouseX >= 145 & mouseY >= 310 && mouseX <= 250 && mouseY <= 340) {
lng = !lng;
} else if(mouseX >= 340 & mouseY >= 320 && mouseX <= 455 && mouseY <= 345) {
qck = !qck;
}
}

``````

## Final Project

Welcome to Covid Retreat!

For this project I was inspired to create a virtual escape due to the restrictions Covid-19 has created. I experimented with sound, location design, a game-like set up.

The program includes 4 locations and you can select your location of choice. Clicking on the icon allows you to enter that location, while pressing the back arrow on your keyboard returns you to the game page. Each location has a unique sound that is supposed to be ambient and relaxing so you can meditate to it. The city backdrop has stars that spin with the mouse X location and the village backdrop has snow falling. These act as additional visual aids.

The poppy field has sounds of birds and how a relaxing field would sound. The beach has the calming noise of waves and seagulls in the distance. The city has street noise as well as ambient jazz street music. The village has noise of wind chimes fluttering in the wind. The pictures of the locations act as aids to visualize the location you’re in, and then you can close your eyes and listen to the sounds to meditate.

graanak-15
``````//This is supposed to be a meditation simulation where you can escape to a location because
// of the restrictions covid has placed on us. Welcome to Covid Retreat!

var homePage = true;
var gamePage = false;
var locationPoppy = false;
var locationBeach = false;
var locationCity = false;
var locationVillage = false;

//image variables
var gpage;
var poppyImg;
var cityImg;
var beachImg;
var villageImg;

//sounds variables
var field;
var beach;
var seagull;
var city;
var jazz;
var chimes;

//snow variables
var xpos = [];
var ypos = [];
var dir = [];

}

function soundSetup() {
field.rate(0.75);
field.setVolume(0.5);
beach.rate(0.5);
beach.setVolume(0.15);
seagull.setVolume(0.1);
city.setVolume(0.5);
jazz.setVolume(1);
chimes.setVolume(1.5);
}

function setup() {
createCanvas(600, 500);
useSound();
//snow setup
for(var i = 0; i < 100; i++){
xpos[i] = random(0, width);
ypos[i] = random(0, height);
dir[i] = random(1, 3);
}
}

function draw() {

//drawing the homepage using p5js commands

if(homePage==true){
background(230);
noStroke();

cube();

fill(255);
textSize(15);
text('Welcome to Covid Retreat. Let us begin your relaxation journey.', 100, 350);

fill(168, 255, 28, 200);
rect(209, 420, 188, 58);
fill(255);
rect(209, 420, 181, 50);

fill(0);
text('Click to start.', 250, 450);

fill(168, 255, 28);
circle(mouseX, mouseY, 5);
fill(168, 255, 28, 200);
circle(mouseX, mouseY, 15);
fill(168, 255, 28, 100);
circle(mouseX, mouseY, 20);

//setting the backdrops for each of the locations
//setting the mouse pointer for the cursor the gamepage

} else if(gamePage==true){
image(gpage, 0, 0, 600, 500);
fill(168, 255, 28);
circle(mouseX, mouseY, 5);
fill(168, 255, 28, 200);
circle(mouseX, mouseY, 15);
fill(168, 255, 28, 100);
circle(mouseX, mouseY, 20);
fill(0);
textSize(10);
text('If you would like to return to this page, press the back arrow on your keyboard.', 75, 100);

} else if(locationPoppy==true){
image(poppyImg, 0, 0, 600, 500);

}else if(locationCity==true){
//creating the stars that rotate with mouseX position for the city backdrop
image(cityImg, 0, 0, 600, 500);
stars(17, 13);
stars(32, 36);
stars(214, 10);
stars(293, 30);
stars(306, 16);
stars(364, 59);
stars(438, 13);
stars(569, 21);

}else if(locationBeach==true){
image(beachImg, 0, 0, 600, 500);

}else if(locationVillage==true){
image(villageImg, 0, 0, 600, 500);
fill(255);
noStroke();
//implementing the snow command
snowing();
}

}

//creating the logo on the homepage
function cube(){
fill(255);
beginShape();
vertex(300, 70);
vertex(390, 145);
vertex(390, 248);
vertex(300, 320);
vertex(209, 248);
vertex(209, 145);
endShape();

fill(220);
beginShape();
vertex(300, 70);
vertex(390, 145);
vertex(300, 210);
vertex(209, 145);
endShape();
}

//causing the screen changes and sound changes for each screen
function mousePressed(){
var my = mouseY;
var mx = mouseX;

if(homePage){
if(mx > 209 & mx < 390 & my > 420 & my < 470){
gamePage = true;
homePage = false;
}
}else if(gamePage){
if(mx > 54 & mx < 139 & my > 132 & my < 217){
locationPoppy = true;
gamePage = false;
field.play();
field.setLoop(true);
} else if(mx > 54 & mx < 139 & my > 336 & my < 421){
locationCity = true;
gamePage = false;
city.play();
city.setLoop(true);
jazz.play();
jazz.setLoop(true);
} else if(mx > 338 & mx < 423 & my > 132 & my < 217){
locationBeach = true;
gamePage = false;
beach.play();
beach.setLoop(true);
seagull.play();
seagull.setLoop(true);
} else if(mx > 338 & mx < 423 & my > 336 & my < 421){
locationVillage = true;
gamePage = false;
chimes.play();
chimes.setLoop(true);
}
}

}

function keyPressed(){
if (keyCode === LEFT_ARROW){
gamePage = true;
locationPoppy = false;
locationBeach = false;
locationCity = false;
locationVillage = false;
field.stop();
beach.stop();
seagull.stop();
city.stop();
jazz.stop();
chimes.stop();
}
}

function snowing(){
for (var i=0; i < xpos.length; i++){
circle(xpos[i], ypos[i], 2);
ypos[i] += dir[i];

if(ypos[i] >= height){
ypos[i] = 0;
}
}
}

function stars(xp, yp){
stroke(255, 239, 143);
push();
translate(xp, yp);
line(-3, 0, 3, 0);
line(0, -3, 0, 3);
pop();
}``````

## Final Project: Electoral Map Swing States

sketch="">
``````//Alyssa Song
//Section C

var trump; //trump and trump 2 are the animations of trump talking
var trump2;
var biden; //biden and biden 2 are the animations of biden talking
var biden2;
var repLead; //decorative marks when trump wins a state
var demLead; //decorative marks when biden wins a state
var trumpWin; //trump illustration when he gets more than 270 votes
var bidenWin; //biden illustration when he gets more tahn 270 votes
var mapUs; //US map of states
var counter = 0;
var mouseCount = 0;

var demVote = 264; //controls democratic electoral votes
var repVote = 232; //controls republican electoral votes

var mouseCountNV = 0; //mousepress count for nevada
var mouseCountPA = 0; //mousepress count for pennsylvania
var mouseCountGA = 0; //mousepress count for georgia

var rx = []; //controls x, y, speed, and color of red confetti
var ry = [];
var rdx = [];
var rc = [];

var dx = []; //controls x, y, speed, and color of blue confetti
var dy = [];
var ddx = [];
var dc = [];

var vNV, vPA, vGA;

}

function setup() {
createCanvas(600, 400);
background(220);
frameRate(10);
textSize(32);

//sets up different speeds, x, y, and color for confetti
for (var i = 0; i < 120; i++) {
rx[i] = random(width);
ry[i] = random(height);
rdx[i] = random(-10, 10);
rc[i] = color(random(150, 255),
random(0, 100), random(0, 50));
dx[i] = random(width);
dy[i] = random(height);
ddx[i] = random(-10, 10);
dc[i] = color(random(0, 100),
random(0, 100), random(150, 255));
}

//create object of states
vNV = vState(0);
vPA = vState(1);
vGA = vState(2);

}

function draw() {
imageMode(CENTER);
strokeWeight(0);

//writes the swing states and number of electoral votes
push();
fill(50);
textSize(12);
text("Pennsylvania: 20 electoral votes", 200, 300);
text("Georgia: 16 electoral votes", 200, 320);
pop();

image(mapUs, 275, 150, 600, 400);
fill(0);

circle(140, 100, 10);

//pennsylvania dot
circle(420, 100, 10);

//georgia dot
circle(390, 180, 10);

if (repVote > demVote) {
image(repLead, 500, 275, 300, 250);
}

//animation of biden and trump talking
if (counter % 2 == 0) {
image(biden, 100, 275, 300, 250);
image(trump2, 500, 275, 300, 250);
}

if (counter % 2 == 1) {
image(biden2, 100, 275, 300, 250);
image(trump, 500, 275, 300, 250);
}

//rep electoral votes display
fill(179, 82, 64);
text(repVote, width - 90, 100);

//dem electoral votes display
fill(75, 108, 199);
text(demVote, 10, 100);

counter++;

electionWin(); //function that displays election winner when they reach 270 votes
}

function mouseClicked() {
mouseCount++;
}

function vState(stateNo) { //defines object
let w = {
state: stateNo,

update: function() {
if (this.state == 0)
updateNV();
else if (this.state == 1)
updatePA();
else if (this.state == 2)
updateGA();
else
print(state);
}

}
return w;
}

function confetti(x, y, dx, c) { //draws confetti
fill(c);
ellipse(x, y, 20, 20);
}

function updateNV() {
if (mouseX > 110 & mouseX < 160 && mouseY > 80 && mouseY < 130) {
var originalRep = 232;
var originalDem = 264;
mouseCountNV++;

if (mouseCountNV % 3 == 0) {
fill(220);
rect(110, 70, 50, 80);
image(mapUs, 275, 150, 600, 400);
demVote = demVote - 6;
}

// 1 is turning state red
if (mouseCountNV % 3 == 1) {
fill(199, 102, 84);
rect(110, 70, 50, 80);
image(mapUs, 275, 150, 600, 400);

repVote = repVote + 6;

}

//2 is turning state blue
if (mouseCountNV % 3 == 2) {
fill(95, 128, 219);
rect(110, 70, 50, 80);
image(mapUs, 275, 150, 600, 400);

demVote = demVote + 6;
repVote = repVote - 6;

}
showLead(mouseCountNV); //shows marks for whoever won the state
}

}

function updatePA() {
if (mouseX > 390 & mouseX < 450 && mouseY > 80 && mouseY < 130) {
mouseCountPA++;

if (mouseCountPA % 3 == 0) {
fill(220);
rect(400, 80, 50, 40);
image(mapUs, 275, 150, 600, 400);
demVote = demVote - 20;

}

// 1 is turn state red
if (mouseCountPA % 3 == 1) {
fill(199, 102, 84);
rect(400, 80, 50, 40);
image(mapUs, 275, 150, 600, 400);

repVote = repVote + 20;

}

//2 is turn state blue
if (mouseCountPA % 3 == 2) {
fill(95, 128, 219);
rect(400, 80, 50, 40);
image(mapUs, 275, 150, 600, 400);

demVote = demVote + 20;
repVote = repVote - 20;

}
}

}

function updateGA() {
if (mouseX > 370 & mouseX < 420 && mouseY > 150 && mouseY < 210) {
mouseCountGA++;

if (mouseCountGA % 3 == 0) {
fill(220);
rect(360, 150, 60, 60);
image(mapUs, 275, 150, 600, 400);
demVote = demVote - 16;

}

// 1 is red
if (mouseCountGA % 3 == 1) {
fill(199, 102, 84);
rect(360, 150, 60, 60);
image(mapUs, 275, 150, 600, 400);

repVote = repVote + 16;

}

//2 is blue
if (mouseCountGA % 3 == 2) {
fill(95, 128, 219);
rect(360, 150, 60, 60);
image(mapUs, 275, 150, 600, 400);

demVote = demVote + 16;
repVote = repVote - 16;

}
}
}

push();
fill(220);
rect(width - 100, 70, 70, 40);
pop();

//republican electoral vote
fill(179, 82, 64);
text(repVote, width - 90, 100);

push();
fill(220);
rect(0, 70, 70, 40);
pop();

//democrat electoral vote
fill(75, 108, 199);
text(demVote, 10, 100);
}

function showLead(state) { //displays mark for whoever won the state
if (state % 3 == 1) {
image(repLead, 500, 275, 300, 250);
}
if (state % 3 == 2) {
image(demLead, 100, 275, 300, 250);
}
}

function electionWin() { //displays whoever wins the election
if (demVote >= 270) { //biden displayed
background(0, 0, 0, 100);

background(75, 108, 199);
for (i = 0; i < 104; i++) {
confetti(dx[i], dy[i], ddx[i], dc[i]);
dx[i] += ddx[i];
if (dx[i] > width || dx[i] < 0) {
ddx[i] = -ddx[i];
}
}

image(bidenWin, 300, 200, 500, 400);

}
if (repVote >= 270) { //trump displayed
background(0, 0, 0, 100);
background(179, 82, 64);
for (i = 0; i < 104; i++) {
confetti(rx[i], ry[i], rdx[i], rc[i]);
rx[i] += rdx[i];
if (rx[i] > width || rx[i] < 0) {
rdx[i] = -rdx[i];
}
}
image(trumpWin, 300, 200, 500, 400);
}
}``````

Alyssa Song

My program is an electoral map of the last few swing states in the 2020 election. You can test the electoral map and use it to see who can win the election based on who wins which swing states, and try different permutations and combinations of states.

For example:

Click Nevada once to turn the state red, and add 6 electoral votes to the republican count.

Next, click Pennsylvania once to turn the state red, which adds 20 electoral votes to the republican count.

Finally, click Georgia once to turn the state red. You should see an image with Trump 2020. Winning Georgia would put Trump over 270 electoral votes, so he would win the election.

To replay the program, refresh the page. Double click on any state to turn the state blue and make Biden win the election.

To use the program, you can click on the dot on the key swing states that are originally grey on the map. Clicking the dot once will turn the state red and add the respective amount of electoral votes to the Republican electoral count on the right, and clicking the dot twice will turn the state blue and do the same thing for the Democratic electoral count on the left.