Final Project: Among Us Social Distancing Game

My final project is an Among Us-themed social distancing game. Among Us is an online multiplayer game that has gained significant popularity over the last several months during the quarantine. In my game, you play as a crewmate moving through the environment (the cafeteria environment from the Among Us game). Other crewmates are running past you and toward you and your goal is to socially distance from them by controlling your character’s movements with the keys. To make it easier to play within the blog the key controls are: W= up, A=left, S= down, and D= right, but in my submission, the character’s movements are controlled by the arrow keys. If one of the other crewmates enters your social distancing bubble (blue transparent circle around your character), you get a strike, and after five strikes you will lose the game. As you advance through the game, there will be more crewmates to avoid, requiring more skill and dexterity with the keys. You will win the game after successfully social distancing for one minute.
You can change your character’s color on the start screen by hitting enter. You can also click to advance to the instructions page and then again into gameplay. When the game is over you can click to play again. Overall, I am really happy with how this game turned out, but given more time I would add a settings page with a difficulty level selector and a sound option you can adjust before you play.

Social Distancing Game
var timer = 60;	//will hold seconds value for countdown (from 60 seconds)
var diams = [];	//holds diamond tiles of cafeteria floor
var lastOdd = false;	//boolean to determine when rows are eliminated
var startx = 270;	//starting x position for your character
var starty = 250	//starting y position for your character
var crewMate = makeCharacter(startx, starty, true);	//your character
var buddies = [];	//array to hold crewmates onscreen
var someoneInside = false	//is someone inside your social distancing bubble?
var counter = 0;	//how many strikes you have
var gameOver = false;	//did you lose?
var win = false;	//did you win?
var setting = 0;	//which screen you are on (0: starting, 1: instruction, 2: gameplay, 3: defeat, 4: victory)
//variables associated with choosing your character's color------------------------------------------------------------
var charcols = ['red', 'orange', 'yellow', 'limegreen', 'green', 'blue', 'cyan', 'hotpink', 'brown', 'gray', 'white']; 
var clr = 0;
var colChoice = 'red';	//this array will hold your character's color
//properties for stars on start screen---------------------------------------------------------------------------------
var starx = []; 
var stary = []; 
var stardx = [];
var starsize = [];
//preload game graphics------------------------------------------------------------------------------------------------
let img;
let winimg;
let startimg;
let instruct;

function preload() {
	img = loadImage('https://i.imgur.com/tMs0pNd.png');
	winimg = loadImage('https://i.imgur.com/ff97vVO.pngs');
	startimg = loadImage('https://i.imgur.com/Yy27NCE.png');
	instruct = loadImage('https://i.imgur.com/lIoslK6.png');
}

function setup() {
    createCanvas(600, 600);
    background(165,167,154);
    //set up the grid for the cafeteria floor tiles
    for (var row=0; row < 7; row++){
    	d_row = []
    	if (row % 2 == 0) {
    		for (var col=0; col < 6; col++){
    			if (col % 2 == 0) {
    				d_row.push(smallDiamond(col*105, row*105+35))
    			}
    			else {
    				d_row.push(bigDiamond(col*105+35, row*105+35)) 
    			}
    		}
    		diams.push(d_row)
    	}
    	else {
    		for (var col=0; col < 7; col++){
    			if (col % 2 == 0){
    				d_row.push(bigDiamond(col*105+35, row*105+35))
    			}
    			else {
    				d_row.push(smallDiamond(col*105, row*105+35))
    			}
    		}
    		diams.push(d_row)
    	}
    }
    //set up the array for the crew members that appear
    for (var i=0; i < 3; i++) {
    	buddies[i] = (makeCrew());
    }
    //set up arrays for stars on start screen
    for (var i=0; i<75; i++)  {
			starx[i]= random(width); 
			stary[i]= random(30, height-30); 
			stardx[i]= random(-5, -1);
			starsize[i] = random(3,8) 	
	}
    frameRate(10);
}

function draw() {
	var frameNum = frameCount
	if (setting == 0) {
		startScreen();
	}
	else if (setting == 1) {
		instructionPage();
	}
	else if (setting == 2) {
		gamePlay();
	}
	else if (setting == 3) {
		GameOver();
	}
	else if (setting == 4) {
		GameWon();
	}
	print('frameNum')
}

function mousePressed() {
	if (setting == 0) {	//proceed through the start screen and instructions to the actual gameplay
		setting = 1
	}
	else if (setting == 1) {	//enter gameplay
		setting = 2;	
	}
	//when the game ends, click to play again
	else if (setting == 3) {	
		gameReset()
		setting = 0
	}
	else if (setting == 4) {
		gameReset()
		setting = 0
	}
}
//display the start screen where you can change your character's color
function startScreen() {
	background(0)
	image(startimg, 0, 0, 600, 600);
	for (i=0; i<75; i++) {
		noStroke();
		fill(255);
		circle(starx[i], stary[i], starsize[i]);
		starx[i] += stardx[i]
	}
	starx.shift()	//shift array, moving first value
	stary.shift()
	starsize.shift()
	stardx.shift()
	var newX = 600; 
	var newY = random(30,height-30); 
	var newDX = random(-10, -5);
	var newSize = random(1,8)
	starx.push(newX);
	stary.push(newY);
	stardx.push(newDX);
	starsize.push(newSize);
	push();
	scale(3.75,3.75);
	translate(50,45)
	AmongUs1(colChoice)
	pop();
}
//pressing ENTER on the start screen will change your character's color
function keyPressed() {
	if (keyCode === ENTER & setting == 0){
	if (clr == 10) {
		clr=0
	}
	else {
		clr++; 
	}
	colChoice = charcols[clr]
	}	
}
//instructions: display the instructions for the game
function instructionPage() {
	background(0);
	image(instruct, 0, 0, 600, 600);
	for (i=0; i<75; i++) {
		noStroke();
		fill(255);
		circle(starx[i], stary[i], starsize[i]);
		starx[i] += stardx[i]
	}
	starx.shift()	//shift array, moving first value
	stary.shift()
	starsize.shift()
	stardx.shift()
	var newX = 600; 
	var newY = random(30,height-30); 
	var newDX = random(-10, -5);
	var newSize = random(1,8)
	starx.push(newX);
	stary.push(newY);
	stardx.push(newDX);
	starsize.push(newSize);
}
//reset the gameplay if you play again
function gameReset() {
	//resetting all sketch variables to original values
	frameNum = frameCount
    timer = 60;
	startx = 270;
	starty = 250
	crewMate = makeCharacter(startx, starty, true);	//starting position for your character
	buddies = [];
	someoneInside = false
	counter = 0;
	gameOver = false;
	win = false;
	charcols = ['red', 'orange', 'yellow', 'limegreen', 'green', 'blue', 'cyan', 'hotpink', 'brown', 'gray', 'white']; 
	clr = 0;
	colChoice = 'red';	//this array will hold your character's color
}
//GAMEPLAY--------------------------------------------------------------------------------------------------------------
function gamePlay() {
	if (timer == 0 & gameOver == false) {
		win = true
		setting = 4
	}
	background(165, 167, 154);
	displayDiamond();
	updateFloor();
	elimRow();
	updateRow();
	crewMate.draw();
	crewMate.update();
	updateRadius();
	drawbuddies();
	removebuddies();
	addMate();
	updatebuddies();
	StrikeCounter();
	Timer();
}
//crewmate constructor
function makeCharacter(x, y, right = true) {
	var c = getColor();
	var guy = {charx: x, chary: y, pos: 1, update: updateCharacter, draw: drawCharacter, col: c, facingRight: right}
	return guy;
}
//ACCESSORIES FOR YOUR CHARACTER---------------------------------------------------------------------------------------
//indicate how far away from others your character needs to be
function socialDistanceBubble(x,y,size) {
	noStroke();
	if (someoneInside == true) {	//if someone is inside your social distance bubble, your bubble turns red
		fill(200,0,0,.1*size)
	}
	else {
		fill(0,0,200,.1*size);
	}
	circle(x, y, size);
}
//function to draw shadow which will appear under your character
function Shadow(x,y) {
	noStroke();
	fill(60,60,60,200);
	ellipse(x, y, 70, 12)
}
//DISPLAY YOUR CHARACTER-----------------------------------------------------------------------------------------------
//display your character with x, y positions and color associated to them
//when you go left, your character will face left
function drawCharacter() {
	socialDistanceBubble(this.charx+30, this.chary+40, 220);
	Shadow(this.charx+30, this.chary+82)
	if (this.facingRight == false){
		push();
		scale(-1,1);
		if (this.pos == 1) {
			push();
			translate(-1*this.charx-60, this.chary);
			AmongUs1(colChoice);
			pop();
		}
		else if (this.pos == 2) {
			push();
			translate(-1*this.charx-60, this.chary);
			AmongUs2(colChoice);
			pop();
		}
		else if (this.pos == 3) {
			push();
			translate(-1*this.charx-60, this.chary);
			AmongUs3(colChoice);
			pop();
		}
		else if (this.pos == 4) {
			push();
			translate(-1*this.charx-60, this.chary);
			AmongUs4(colChoice);
			pop();
		}
		else {
			push();
			translate(-1*this.charx-60, this.chary);
			AmongUs5(colChoice);
			pop();
		}
		pop();
	}
	if (this.facingRight == true) {
		if (this.pos == 1) {
			push();
			translate(this.charx, this.chary);
			AmongUs1(colChoice);
			pop();
		}
		else if (this.pos == 2) {
			push();
			translate(this.charx, this.chary);
			AmongUs2(colChoice);
			pop();
		}
		else if (this.pos == 3) {
			push();
			translate(this.charx, this.chary);
			AmongUs3(colChoice);
			pop();
		}
		else if (this.pos == 4) {
			push();
			translate(this.charx, this.chary);
			AmongUs4(colChoice);
			pop();
		}
		else {
			push();
			translate(this.charx, this.chary);
			AmongUs5(colChoice);
			pop();
		}
	}
}
//UPDATE YOUR CHARACTER'S POSITION-----------------------------------------------------------------------------
//update the among us character function drawn so the guy looks like he is walking
//you can control your character with the arrow keys
//your character cannot travel outside the boundaries of the screen
function updateCharacter(){
	if (keyIsDown(65) & this.charx > 20) {	//"A"
    	this.facingRight = false
    	this.charx -= 10;
  	}
  	if (keyIsDown(68) & this.charx < 540) {	//"D"
    	this.facingRight = true
    	this.charx += 10;
  	}
  	if (keyIsDown(87) & this.chary > 5) {	//"W"
    	this.chary -= 10;
  	}
  	if (keyIsDown(83) & this.chary < 520) {	//"S"
    	this.chary += 10;
  	}
	if (this.pos == 5){
		this.pos = 1;
	}
	else {
		this.pos += 1;
	}
}
//CHECK IF SOMEONE IS INSIDE YOUR SOCIAL DISTANCING BUBBLE------------------------------------------------------------
//update position of crewmate relative to your character
function updateRadius() {
	var inRad = false
	for (var i = 0; i < buddies.length; i++) {
		d = dist(buddies[i].charx, buddies[i].chary, crewMate.charx, crewMate.chary);
		if (d < 110) {
			inRad = true;
		}
	}
	if (inRad == true) {
		if (someoneInside ==  false) {
			counter++;
			if (counter == 5) {
				gameOver = true
				setting = 3
			}
			if (timer == 0 & counter < 5 && gameOver == false) {
				win = true
				setting = 4
			}
		}
		someoneInside = true;
	}
	else {
		someoneInside = false;
	}
}
//GAME FEATURES-------------------------------------------------------------------------------------------------------
//displays the strikes in the bottom left
function StrikeCounter() {	
	stroke(255)
	fill(0)
	strokeWeight(3)
	rect(20,550,160,35);
	noStroke()
	textStyle(BOLD);
	textSize(32);
	fill('#bf0000');	//dark red color for the X's
	if (counter == 1) {
		text('X', 40, 570);
	}
	if (counter == 2) {
		text('X', 40, 570);
		text('X', 70, 570);
	}
	if (counter == 3) {
		text('X', 40, 570);
		text('X', 70, 570);
		text('X', 100, 570);
	}
	if (counter == 4) {
		text('X', 40, 570);
		text('X', 70, 570);
		text('X', 100, 570);
		text('X', 130, 570);
	}
	if (counter == 5) {
		text('X', 40, 570);
		text('X', 70, 570);
		text('X', 100, 570);
		text('X', 130, 570);
		text('X', 160, 570);
	}
}
//display game timer in bottom right corner (countdown from 60 seconds)
function Timer() {
	var frameNum = frameCount
	stroke(255)
	fill(0);
	if (timer <= 10) {
		//noStroke();
		fill('#bf0000')
		textStyle(BOLD)
	}
	textFont('Arial Narrow')
	textAlign(CENTER, CENTER);
  	textSize(32);
  	text(timer, width-25, 570);
  	if (frameNum % 10 == 0) { 
    	timer --;
  	}
}
//displays when game is lost
function GameOver() {
	if (gameOver == true) {
		image(img, 0, 0, 600, 600);
		push();
		scale(5,5);
		translate(25,20)
		Dead1(colChoice)
		pop();
		textFont('Arial Narrow')
		textStyle(NORMAL)
		textAlign(CENTER, CENTER);
	  	textSize(35);
	  	fill(255)
	  	noStroke();
		text('Click to play again', width/2, 550)
		setting = 3
	}
}
//displays when game is won
function GameWon() {
	if (win == true) {
		image(winimg, 0, 0, 600, 600);
		push();
		scale(5,5);
		translate(25,25)
		AmongUs1(colChoice)
		pop();
		textFont('Arial Narrow')
		textStyle(NORMAL)
		textAlign(CENTER, CENTER);
	  	textSize(35);
	  	fill(255)
	  	noStroke();
		text('Click to play again', width/2, 550)	
		setting = 4
	}
}
//CREW (PROPERTIES OF OTHER CREWMATES)-----------------------------------------------------------------------------------
//display crew with x, y positions and color associated to them
function drawCrew() {
	if (this.fig == 0) {
		if (this.pos == 1) {
			push();
			translate(this.charx, this.chary)
			AmongUs1(this.col);
			pop();
		}
		else if (this.pos == 2) {
			push();
			translate(this.charx, this.chary)
			AmongUs2(this.col);
			pop();
		}
		else if (this.pos == 3) {
			push();
			translate(this.charx, this.chary)
			AmongUs3(this.col);
			pop();
		}
		else if (this.pos == 4) {
			push();
			translate(this.charx, this.chary)
			AmongUs4(this.col);
			pop();
		}
		else {
			push();
			translate(this.charx, this.chary)
			AmongUs5(this.col);
			pop();
		}
	}
	else {
		push();
		translate(this.charx, this.chary)
		Dead1(this.col);
		pop();
	}
}
//updates crewmate positions with different speeds (to go down canvas if walking and up if dead)
function updateCrew() {
	if (this.fig == 0) {
		this.chary += this.speed;
		if (this.pos == 5) {
			this.pos = 1;
		}
		else {
			this.pos += 1
		}
	}
	else {
		this.chary -= this.speed;
	}
}
//choose a random x position for newly generated crewmates
function getX() {
	var x = random(20, 530)
	if (x >= 160) {
		x += 70;
	}
	else {
		x -= 20;
	}
	return x;
}
//choose starting position at top of canvas for walking crewmates and bottom for dead crewmates so it looks like they are all moving with the screen
function start(f) {
	if (f == 0) {
		return 0
	}
	else {
		return 600
	}
}
//return a random speed from the array, to be assigned to individual crewmate
function getVelocity(status) {
	if (status == 0){
		return Math.floor(random(1,6));
	}
	else {
		return 5;
	}
}
//return a random color from the array, to be assigned to individual crewmate
//other crewmates will not have the same color as your character
function getColor() {
	var cols = ['red', 'orange', 'yellow', 'limegreen', 'green', 'blue', 'cyan', 'hotpink', 'brown', 'gray', 'white'];
	var index = Math.floor(Math.random() * cols.length); 
	while (colChoice == cols[index]) {
		index = Math.floor(Math.random() * cols.length)
	}
	return cols[index]
}
//assign object properties to the crew (crewmates onscreen)
function makeCrew() {
	var x = getX();
	var f = Math.floor(random(0,2));
	var y = start(f);
	var v = getVelocity(f);
	var c = getColor();
	var crew = {charx: x, chary: y, speed: v, update: updateCrew, pos: 1, fig: f, draw: drawCrew, col: c}
	return crew
}
//draw new crewmates
function drawbuddies() {
	for (var i=0; i < buddies.length; i++){
		buddies[i].draw();
	}
}
//update position of new crewmates
function updatebuddies() {
	for (var i=0; i < buddies.length; i++){
		buddies[i].update();
	}
}
//remove crewmates as they pass offscreen
function removebuddies() {
	keep = []
	for (var i=0; i < buddies.length; i++){
		if (buddies[i].chary +600 > 0) {
			keep.push(buddies[i])
		}
	}
	buddies = keep;
}
//add new crewmates with a probability based on the stage (increasing difficulty every 15 seconds)
function addMate() {
	var threshold;
	if (60>timer & timer>=45) {
		threshold = 0.02
	}
	if (45>timer && timer>=30) {
		threshold = 0.045
	}
	if (30>timer && timer>=15) {
		threshold = 0.055
	}
	if (15>timer && timer>=0) {
		threshold = 0.06
	}
	if (random(0,1) < threshold) {
		buddies.push(makeCrew())
	}
}
//CHARACTER DRAWING-----------------------------------------------------------------------------------------------------
//draw all the stages of walking for one crewmate
function AmongUs1(c) {
	stroke(0);
	strokeWeight(5);
	fill(c)
	//backpack
	beginShape();
	curveVertex(16,23);
	curveVertex(4,28);
	curveVertex(4,57);
	curveVertex(18,62);
	endShape(CLOSE);
	//body
	beginShape();
	curveVertex(20,9);
	curveVertex(15,29);
	curveVertex(15,64);
	curveVertex(21,77);
	curveVertex(32,75);
	curveVertex(33,63);
	curveVertex(39,63);
	curveVertex(42,75);
	curveVertex(52,72);	//front of foot
	curveVertex(57,60);
	curveVertex(56,42);
	curveVertex(59,24);
	curveVertex(50,10);
	curveVertex(35,3);
	endShape(CLOSE);
	//goggles
	fill(204,227,238);
	beginShape();
	curveVertex(31,16);
	curveVertex(56,18);
	curveVertex(59,29);
	curveVertex(55,33);
	curveVertex(32,33);
	curveVertex(24,24);
	endShape(CLOSE);
}

function AmongUs2(c) {
	stroke(0);
	strokeWeight(5);
	fill(c)
	//backpack
	beginShape();
	curveVertex(16,23);
	curveVertex(4,28);
	curveVertex(4,57);
	curveVertex(18,62);
	endShape(CLOSE);
	//back leg
	beginShape();
	curveVertex(15,57);
	curveVertex(5,68);
	curveVertex(19,78);
	curveVertex(34,63);
	endShape(CLOSE);
	//body
	beginShape();
	curveVertex(22,6);
	curveVertex(15,30);
	curveVertex(15,56);
	curveVertex(24,65);
	curveVertex(34,65);
	curveVertex(42,66);
	curveVertex(55,79);
	curveVertex(68,70);
	curveVertex(52,59);	//front of foot
	curveVertex(55,47);
	curveVertex(55,34);
	curveVertex(58,21);
	curveVertex(47,7);
	curveVertex(33,2);
	endShape(CLOSE);
	//goggles
	fill(204,227,238);
	beginShape();
	curveVertex(31,16);
	curveVertex(56,18);
	curveVertex(59,29);
	curveVertex(55,33);
	curveVertex(32,33);
	curveVertex(24,24);
	endShape(CLOSE);
}
function AmongUs3(c) {
	stroke(0);
	strokeWeight(5);
	fill(c)
	//backpack
	beginShape();
	curveVertex(16,23);
	curveVertex(4,28);
	curveVertex(4,57);
	curveVertex(18,62);
	endShape(CLOSE);
	//back leg
	beginShape();
	curveVertex(46,56);
	curveVertex(48,73);
	curveVertex(19,72);
	curveVertex(19,62);
	endShape(CLOSE);
	//body
	beginShape();
	curveVertex(19,10);
	curveVertex(15,35);
	curveVertex(17,61);
	curveVertex(25,68);
	curveVertex(28,75);
	curveVertex(24,83);
	curveVertex(36,82);
	curveVertex(41,71);
	curveVertex(39,60);	//front of foot
	curveVertex(49,58);
	curveVertex(57,50);
	curveVertex(56,35);
	curveVertex(58,25);
	curveVertex(54,14);
	curveVertex(45,8);
	curveVertex(32,4);
	endShape(CLOSE);
	//goggles
	fill(204,227,238);
	beginShape();
	curveVertex(31,16);
	curveVertex(56,18);
	curveVertex(59,29);
	curveVertex(55,33);
	curveVertex(32,33);
	curveVertex(24,24);
	endShape(CLOSE);
}
function AmongUs4(c) {
	stroke(0);
	strokeWeight(5);
	fill(c)
	//backpack
	beginShape();
	curveVertex(16,23);
	curveVertex(4,28);
	curveVertex(4,57);
	curveVertex(18,62);
	endShape(CLOSE);
	//back leg
	beginShape();
	curveVertex(40,60);
	curveVertex(56,79);
	curveVertex(66,65);
	curveVertex(54,52);
	endShape(CLOSE);
	//body
	beginShape();
	curveVertex(25,4);
	curveVertex(16,24);
	curveVertex(15,54);
	curveVertex(19,61);
	curveVertex(8,61);
	curveVertex(5,74);
	curveVertex(19,76);
	curveVertex(28,69);
	curveVertex(32,63);	//front of foot
	curveVertex(45,63);
	curveVertex(56,56);
	curveVertex(58,38);
	curveVertex(58,26);
	curveVertex(54,12);
	curveVertex(43,3);
	endShape(CLOSE);
	//goggles
	fill(204,227,238);
	beginShape();
	curveVertex(31,16);
	curveVertex(56,18);
	curveVertex(59,29);
	curveVertex(55,33);
	curveVertex(32,33);
	curveVertex(24,24);
	endShape(CLOSE);
}
function AmongUs5(c) {
	stroke(0);
	strokeWeight(5);
	fill(c)
	//backpack
	beginShape();
	curveVertex(16,23);
	curveVertex(4,28);
	curveVertex(4,57);
	curveVertex(18,62);
	endShape(CLOSE);
	//back leg
	beginShape();
	curveVertex(32,61);
	curveVertex(34,76);
	curveVertex(49,76);
	curveVertex(50,56);
	endShape(CLOSE);
	//body
	beginShape();
	curveVertex(24,3);
	curveVertex(17,24);
	curveVertex(16,51);
	curveVertex(15,59);
	curveVertex(23,59);
	curveVertex(10,64);
	curveVertex(12,72);
	curveVertex(32,70);
	curveVertex(37,62);	//front of foot
	curveVertex(49,62);
	curveVertex(56,54);
	curveVertex(58,34);
	curveVertex(58,23);
	curveVertex(54,13);
	curveVertex(47,5);
	curveVertex(35,1);
	endShape(CLOSE);
	//goggles
	fill(204,227,238);
	beginShape();
	curveVertex(31,16);
	curveVertex(56,18);
	curveVertex(59,29);
	curveVertex(55,33);
	curveVertex(32,33);
	curveVertex(24,24);
	endShape(CLOSE);
}
//draw a dead crewmate
function Dead1(c) {
	stroke(0);
	strokeWeight(5);
	fill(255);
	//bone sticking out
	beginShape();
	curveVertex(33,39);
	curveVertex(32,29);
	curveVertex(27,22);
	curveVertex(32,18);
	curveVertex(35,23);
	curveVertex(37,17);
	curveVertex(41,21);
	curveVertex(38,32);
	curveVertex(38,42);
	endShape(CLOSE);
	fill(c);
	//arm
	beginShape();
	curveVertex(2,39);
	curveVertex(12,34);
	curveVertex(20,38);
	curveVertex(18,60);
	curveVertex(6,59);
	endShape(CLOSE);
	//half body
	beginShape();
	curveVertex(15,37);
	curveVertex(28,40);
	curveVertex(34,37);
	curveVertex(44,40);
	curveVertex(58,38);
	curveVertex(57,66);
	curveVertex(45,74);
	curveVertex(41,62);
	curveVertex(35,62);
	curveVertex(32,74);
	curveVertex(17,73);
	curveVertex(14,49);
	endShape(CLOSE);
}
//BACKGROUND-------------------------------------------------------------------------------------------------------------
//draw the cafeteria floor
//make small diamond tile object
function smallDiamond(x, y) {
	var diamond = {diamondx: x, diamondy: y, diamondw: 70, diamondh: 35, speed: -5.0, draw: drawDiamond, update: updateDiamond}
	return diamond;
}
//draw small diamond
function drawDiamond() {
	noStroke();
	fill(133,135,124);
	beginShape();
	vertex(this.diamondx,this.diamondy);
	vertex(this.diamondx+this.diamondw/2,this.diamondy-this.diamondh);
	vertex(this.diamondw+this.diamondx, this.diamondy);
	vertex(this.diamondx+this.diamondw/2,this.diamondy+this.diamondh);
	endShape(CLOSE);
}
//update position of the tile with speed
function updateDiamond() {
	this.diamondy += this.speed;
}
//make big diamond tile object
function bigDiamond(cx, cy) {
	var bigdiam = {leftD: smallDiamond(cx-70, cy), topD: smallDiamond(cx-35, cy-35), rightD: smallDiamond(cx, cy), bottomD: smallDiamond(cx-35, cy+35), draw: drawBigDiamond, update: updateBigDiamond}
	return bigdiam;
}
//make big diamond tile from smaller diamond tiles
function drawBigDiamond() {
	this.leftD.draw()
	this.topD.draw()
	this.rightD.draw()
	this.bottomD.draw()
}
//update position of big diamond tiles
function updateBigDiamond() {
	this.leftD.update();
	this.topD.update();
	this.rightD.update();
	this.bottomD.update();
}
//draw the diamonds
function displayDiamond() {
	for (var i=0; i < diams.length; i++){
		for (var j=0; j < diams[i].length; j++){
			diams[i][j].draw();
		}
	}
}
//update the positons of the diamonds as the screen scrolls
function updateFloor() {
	for (var i=0; i < diams.length; i++) {
		for (var j=0; j < diams[i].length; j++) {
			diams[i][j].update();
		}
	}
}
//get rid of rows that have slipped offscreen
function elimRow(){
	keepRow = false;
	for (var i=0; i < diams[0].length; i++) {
		if (lastOdd == false){
			if (i % 2 == 0) {
				if (diams[0][i].diamondy + diams[0][i].diamondh > 0) {
					keepRow = true
				}
			}
			else {
				if (diams[0][i].bottomD.diamondy + diams[0][i].bottomD.diamondh > 0){
					keepRow = true
				}
			}
		}
		else {
			if (i % 2 == 0) {
				if (diams[0][i].bottomD.diamondy + diams[0][i].bottomD.diamondh > 0){
					keepRow = true
				}
			}
			else {
				if (diams[0][i].diamondy + diams[0][i].diamondh > 0){
					keepRow = true
				}
			}
		}
	}
	if (keepRow == false){
		diams.shift();
	}
}
//update the new rows added such that they match the original cafeteria tile pattern
function updateRow() {
	if (diams.length < 7){
		n_row = []
		if (lastOdd == true){
			for (var col=0; col < 7; col++){
				if (col % 2 == 0) {
	    			n_row.push(smallDiamond(col*105, 665))
	    		}
	    		else {
	    			n_row.push(bigDiamond(col*105+35, 665)) 
	    		}
			}
			diams.push(n_row);
			lastOdd = false;
		}
		else {
			for (var col=0; col < 7; col++){
	    		if (col % 2 == 0){
	    			n_row.push(bigDiamond(col*105+35, 665))
	    		}
	    		else {
	    			n_row.push(smallDiamond(col*105, 665))
	    		}
	    	}
	    	diams.push(n_row);
	    	lastOdd = true;
		} 
	}
}

Final Project: Reminders from the Room

finalproject-cb
//Caitlyn Baensch
//cbaensch@andrew.cmu.edu
//Section D

var shelf;
var bedroom;
var wind;
var steam;
var birds = [];
var fish = [];
var enter = false;
var phoneon = false;
var fadeg = 140;
var fadeb = 150;
var steamy = 266;
var steamdy = .5;

//load illustrations
function preload() {
    shelf = loadImage("https://i.imgur.com/FCmktLo.png");
    bedroom = loadImage("https://i.imgur.com/WVYB6XA.png");
    wind = loadImage("https://i.imgur.com/qjTV5Rs.png");
    steam = loadImage("https://i.imgur.com/k561c6E.png");
}

function setup() {
    createCanvas(600, 425);
    
    //setup for birds
    for(var i = 0; i < 6; i++) {
        birdsx = random(width);
        birds[i] = makeBirds(birdsx);
    }

    //setup for fish
    for (var i = 0; i < 12; i++) {
        fishx = random(325, 385);
        fish[i] = makeFish(fishx);
    }

    frameRate(12);
    angleMode(DEGREES);
}

function draw() {
    background(0);

    //show intro screen with instructions
    intro();

    //show the room when enter button is clicked
    if(enter == true) {
        room();
    }
}


//birds helper functions
//update the bird positions and display them
function displayBirds() {
    for (var i = 0; i < birds.length; i++) {
        birds[i].move();
        birds[i].draw();
    }
}

//remove birds that are off the canvas from the array
function removeBirds() {
    var birdsToKeep = [];
    for (var i = 0; i < birds.length; i++) {
        if (birds[i].x + birds[i].w > 0) {
            birdsToKeep.push(birds[i]);
        }
    }
    birds = birdsToKeep;
}

//with a small probability, add a new bird to end of the array
function addNewBirds() {
    var newBirdLikelihood = 0.12;
    if (random(0,1) < newBirdLikelihood) {
        birds.push(makeBirds(width+20));
    }
}

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

function drawBird() {
    push();
    translate(this.x, this.y);
    fill(249, 228, 222);
    noStroke();
    triangle(0, 0, this.w, -this.h, this.w, 0);
    triangle(0, 0, this.w/2, -this.h, this.w/2, 0);
    pop();
}

//bird constructor (random location, size, and speed)
function makeBirds(birdsx) {
    var b = {x: birdsx, y: random(height),
            w: random(8, 16), h: random(4, 8),
            speed: random(-5, -10),
            move: moveBird,
            draw: drawBird
    }
    return b;
}


//fish helper functions
function displayFish() {
    for (var i=0; i<fish.length; i++) {
        fish[i].move();
        fish[i].draw();
    }
}

function moveFish() {
    this.x += this.dx;
    if (this.x > 385 || this.x < 325) {
        this.dx = -this.dx;
    }
}

function drawFish() {
    noStroke();
    fill(this.c);
    ellipse(this.x, this.y, this.w, this.h);
    if (this.dx < 0) {
        triangle(this.x+3, this.y, this.x+6, this.y-3, this.x+6, this.y+3);
    } else {
        triangle(this.x-3, this.y, this.x-6, this.y-3, this.x-6, this.y+3);
    }
}

//fish constructor (random location, size, speed, and color)
function makeFish(fishx) {
    var f = {x: fishx, y: random(195, 240),
        w: random(8, 12), h: random(3, 7),
        dx: random(-3, 3),
        c: color(random(100, 255), random(100, 255), random(100, 255)),
        move: moveFish,
        draw: drawFish
    }
    return f;
}


//wall clock function
function clock() {
    var hr = hour();
    var mn = minute();
    var sc = second();

    //second hand
    strokeWeight(2.15);
    var s = map(sc, 0, 60, 0, 360);
    push();
    rotate(s);
    stroke(255, 176, 148);
    line(0, 0, 16, 0);
    pop();

    //minute hand
    var m = map(mn, 0, 60, 0, 360);
    push();
    rotate(m);
    stroke(110, 160, 133);
    line(0, 0, 14, 0);
    pop();

    //hour hand
    var h = map(hr % 12, 0, 12, 0, 360);
    push();
    rotate(h);
    stroke(110, 160, 133);
    line(0, 0, 10, 0);
    pop();
}


//interactions for tip screens helper functions
//headphones: listen to music
function headphones() {
    if (mouseX > 22 & mouseX < 80 && mouseY > 150 && mouseY < 170) {
        tip('Listen to your favorite music.', 'Listening to music can help you focus, feel better, and relax.');
    }
}

//journals: reflect
function journals() {
    if (mouseX > 73 & mouseX < 102 && mouseY > 110 && mouseY < 122) {
        tip('Reflect on how you are feeling.', 'Try keeping a journal or taking some time each day to check in with yourself.');
    }
}

//tea: stay hydrated
function tea() {
    if (mouseX > 113 & mouseX < 134 && mouseY > 287 && mouseY < 308) {
        tip('Stay hydrated with water or a cup of hot tea.', 'Being well-hydrated improves sleep quality, cognition, and mood.');
    }
}

//phone: check in with friends
function phone() {
    if (mouseX > 137 & mouseX < 171 && mouseY > 303 && mouseY < 312) {
        tip('Check in with friends and family.', 'Catch up over text or phone call and see how everyone is doing.');
    }
}

//window: go for a walk
function win() {
    if (mouseX > 158.5 & mouseX < 268.5 && mouseY > 107 && mouseY < 217) {
        tip('Go outside for a 10-minute walk.', 'A walk can improve your mood and cognitive function as well as reduce stress.');
    }
}

//fish tank and cat: spend time with pets
function pets() {
    if ((mouseX > 313 & mouseX < 401 && mouseY > 187 && mouseY < 251) || (mouseX > 543 && mouseX < 594 && mouseY > 245 && mouseY < 274)) {
        tip('Spend time with pets.', 'Some quality time with your animal friends is sure to make you smile.');
    }
}

//books: read a book
function books() {
    if (mouseX > 325 & mouseX < 367 && mouseY > 278 && mouseY < 308) {
        tip('Get lost in a book.', 'Reading is the perfect way to unwind. Try it before bed instead of using your phone.');
    }
}

//yoga mat: stretch
function yoga() {
    if (mouseX > 318 & mouseX < 600 && mouseY > 378 && mouseY < 425) {
        tip('Take a break and stretch.', 'Doing yoga can help break up long periods of sitting at a desk and clear your mind.');
    }
}

//decorations: surround yourself with things that make you happy
function decoration() {
    if ((mouseX > 314 & mouseX < 378 && mouseY > 122 && mouseY < 174) || (mouseX > 468 && mouseX < 496 && mouseY > 182 && mouseY < 212)) {
        tip('Surround yourself with things you love.', 'Decorate your space with photos, art, and other meaningful items. Avoid clutter!');
    }
}

//clock: keep a daily routine
function time() {
    if (mouseX > 521 & mouseX < 572 && mouseY > 112 && mouseY < 163) {
        tip('Keep a daily routine.', 'Having a daily routine can reduce anxiety and create rhythm in your day.');
    }    
}


//text formatting for headers
function header() {
    textSize(24);
    textStyle(BOLD);
    textFont('Avenir');
}

//text formatting for body
function body() {
    textSize(14);
    textStyle(NORMAL);
    textFont('Avenir');
}


//tip screens formatting
function tip(line1, line2) {
    background(250, 227, 221, 230);
    fill(237, 122, 93);
    header();
    text(line1, 40, 250);
    body();     
    text(line2, 40, 285);
}


//intro opening screen with title and instructions
function intro() {
    background(255, 136, 108);
    fill(250, 227, 221);
    image(shelf, 40, 100, 286, 95);
    textSize(36);
    textStyle(BOLD);
    textFont('Avenir');
    text('Reminders from the Room', 40, 250);
    body();    
    text('Some quick tips for working from home during the pandemic.', 40, 285);
    text('Enter and hover over elements in the illustration to see relevant tips and info.', 40, 302);
    noStroke();
    fill(250, 227, 221);
    rect(456, 335, 100, 38, 38);
    fill(255, 136, 108);
    header();
    text('Enter', 476.5, 362);
    //if enter button is hovered over
    if (mouseX > 456 & mouseX < 555 && mouseY > 335 && mouseY < 373) {
        fill(244, 181, 161);
        rect(456, 335, 100, 38, 38);
        fill(237, 122, 93);
        header();
        text('Enter', 476.5, 362);
    }
}

//if enter button is pressed, enter the room
function mousePressed() {
    if (mouseX > 456 & mouseX < 555 && mouseY > 335 && mouseY < 373) {
        enter = true;
        room();
    }
}


//room environment
function room() {
    //landscape outside window
    image(wind, 146, 100, 125, 116);
    
    //birds flying outside window
    displayBirds();
    removeBirds();
    addNewBirds();

    //bedroom
    image(bedroom, 0, 0, width, height);

    //fish swimming in fish tank
    push();
    displayFish();
    fill(178, 190, 209, 50);
    rect(326, 187, 74, 56);
    pop();

    //wall clock by bed ticking
    push();
    translate(545, 138);
    rotate(-90);
    clock();
    pop();

    //phone screen new notifications
    push();
    noStroke();
    fill(37, 66, 52);
    quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
    if (frameCount % 90 == 0) {
        phoneon = true;
        if (phoneon == true) {
            fadeg = 240;
            fadeb = 240;
            fill(249, fadeg, fadeb);
            quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
        }
    } else {
        if (fadeg >= 140 & fadeb >= 150) {
            fadeg = fadeg - 3;
            fadeb = fadeb - 3;
            fill(249, fadeg, fadeb);
            quad(140, 303.5, 165, 303.5, 167, 308, 139, 308);
            phoneon = false;
        }
    }
    pop();

    //steam floats up over cup of tea
    image(steam, 115, steamy, 14, 24);
    steamy -= steamdy;
    if (steamy <= 257 || steamy > 267) {
        steamdy = -steamdy;
    }

    //show tip screens for user interaction
    headphones();
    journals();
    tea();
    phone();
    win();
    pets();
    books();
    yoga();
    decoration();
    time();
}

For my final project, I made an interactive illustration featuring tips for working from home during the pandemic. With hours spent locked up inside in endless Zoom meetings, I think that Zoom fatigue, a warped sense of time, and feelings of stress and anxiety are all common sentiments. I want to bring awareness to these challenges and offer simple strategies to combat fatigue and stress. I wanted my program to have a relaxing and calming feeling to it, so I chose a light, playful color palette for my illustrations as well as used an inviting typeface.

To interact with my program, follow the instructions on the intro screen. Click the “Enter” button to enter the room and explore the environment. Hover over different elements in the animated illustration to view relevant tips and information.

If I had more time, I might consider adding sound to some of the elements in the room. I would also maybe think about adding illustrations/animations to the advice screens and using p5.js to create patterns on objects or wallpaper.

Final Project

sketch
/*
Bon Bhakdibhumi
bbhakdib
Section D
*/

var particles = [];


function setup() {
    createCanvas(400, 400);
    for (var i = 0; i < 50; i ++) {
        particles[i] = new Object();
        particles[i].x = random(width);
        particles[i].y = random(height);
        particles[i].dx = random(-2,5);
        particles[i].dy = random(-2,5);
        particles[i].c = color(86, 137, 179);
        particles[i].covid = false;
    }
    frameRate(25);
}

function draw() {
    background(201, 156, 105);
    for (var j = 0; j < 50; j ++) {
        drawParticles(particles[j]);
        moveParticles(particles[j]);
    }
    if (frameCount == 50 || frameCount % 100 == 0) {
        particles[2].covid = true;
    }
// calculate distance for infection
    for (var i = 0; i < particles.length; i ++) {
        for (var j = 0; j < particles.length; j ++) {
            var d = int(dist(particles[i].x, particles[i].y, particles[j].x, particles[j].y));
            if (d < 20) {
                if (particles[i].covid == true) {
                    particles[j].covid = true;
                }
            }
        }
    }
// display counter
//if all particles have covid, then display the warning text
     var covidCounter = 0;
    for (var i = 0; i < particles.length; i ++) {
        if (particles[i].covid == true) {
            covidCounter ++;
        }
    }
    noStroke();
    fill(255);
    textAlign(LEFT);
    textSize(20);
    text("Infected People:", 10, 25);
    text(covidCounter, 160, 25);
    if (covidCounter == particles.length) {
        fill(255, 253, 131);
        textAlign(CENTER);
        textSize(30);
        text('STOP CORONA!', width/2, height/2.15);
        textSize(35)
        text('KEEP YOUR DISTANCE!', width/2, height/1.75);
    }
}

// reset canvas and cure all particles
function keyPressed() {
        for (var i = 0; i < particles.length; i ++) {
            particles[i].covid = false;
        }
}

// cure covid with mouse
function mousePressed() {
    for (var i = 0; i < particles.length; i ++) {
        var mouseDistance = int(dist(mouseX, mouseY, particles[i].x, particles[i].y));
        if (mouseDistance < 10) {
            particles[i].covid = false;
        }
    }
}

function drawParticles(p) {
    if (p.covid == true) {
        stroke(1);
        fill(204, 61, 61);
    } else {
        stroke(1);
        fill(p.c);
    }
    ellipse(p.x, p.y, 12, 12);
}

function moveParticles(p) {
    p.x += p.dx;
    p.y += p.dy;
    if (p.x > width || p.x < 0) {
        var resetX = random(100);
        if (resetX < 50) {
            p.x = 0;
        } else {
            p.x = width;
        }
    p.dx = random(-2, 5);
    }
    if (p.y > height || p.y < 0) {
        var resetY = random(100);
        if (resetY < 50) {
            p.y = 0;
        } else { 
            p.y = height;
        }
    p.dy = random(-2, 5);
    }
}

The final result of my project is a Covid-19 infection simulator using particles. The canvas represents a public space, and the particles represent people traveling around without social distancing.  Initially, all the particles are not infected. However, as they “travel” around freely–some going off canvas and reentering the canvas from somewhere else–one of the particles would contract “Covid-19, ” turning red. This infected particle will then continue to spread the virus to other particles if other particles are too close–“less than 6 feet”–to it. A counter is displayed at the top left of the canvas, showing how many particles are infected on the screen at the moment. Once every particle is infected, a text is displayed saying “STOP CORONA! KEEP YOUR DISTANCE!”This program is also interactive. Using the mousePressed() function, when the user clicks on an infected particle, he or she can cure it from the virus. However, the particles can become infected again similar to Covid reinfections we have seen on the news. By clicking on any key, the user can also reset the particles to their normal state, restarting the simulation again.

The project is inspired by the frustration I get from watching the news and seeing people not properly social distancing. Hopefully, this project illustrates the importance of social distancing to the viewers while providing them with visual elements that are captivating and interactive. 

If provided more time, I would like to add mutual repulsion to the program, illustrating what effective social distancing looks like, which was one of the main features I planned to implement initially but failed to do so since I didn’t fully understand the physics behind the example code and didn’t want a completely broken program.

Final Project: COVID cases and temperatures

https://editor.p5js.org/ssahasra/present/mf6vOSPgw

This is a video of the Final p5.js program.

The idea was to correlate temparatures and COVID cases of two months far apart from each other in the year 2020.

I used arrays to fill in the values of the number of cases (height of bar) with loops and used the buttons [mouse interactions] and array, objects to create effects of different weather conditions. For some of the weather effects I sourced code from current projects on the internet.

[This was the very first version, and evolved to a much different version with iteration after I received feedback from the Instructor and TAs

After receiving feedback on my proposal, I made two key changes:

1. Instead of using files to load data I added the values to indices of an array, to create a data visualization + monthly calendar that shows the number of COVID cases

2. I made it more relevant to the theme of 2020. Earlier I was working only with temperature data, but now I decided to represent the relationship between temperature and COVID cases.

The central idea of my projects is to create an interactive visualization + calendar that allows the viewer to compare different months of the year and see how temperature affects the rise in COVID cases (although there are of course other factors for the rise) Furthermore, I want to use mouse interactions to filter certain days when temperatures are in particular range using the buttons on the right (see diagram and code). I am still in the process of adding interactivity and controls using the <function mousePressed()> Optionally, a hover state over one or two of the bars (if time permits, to show the temperature and number of COVID cases to make it a more realistic visualisation)

When the button is pressed, some bar graphs that are not in that temperature range, will disappear and I want to use random motion, I learnt in class to create effects of snow, rain, sun etc in the background of each month. If I am successful in this, as a next step, I would also like to add sound files that create sound effects along with the visual effects of the weather. For the visual effects, my plan is to use the code I used for the snow and change parameters, color, speed etc, to create the other weather effects. For examples: raindrops will be blue and would sway less, and fall down in straighter lines than snow.

Below is the code snippet for the entire final program:

let lastFramePress = false;
let toggle = false;
let value = 0;
let button;
let snowflakes = []; // array to hold snowflake objects
let rain = [];

let snow ;







mayCases = [1540, 1307, 1008, 913, 975, 1022, 1160, 1352, 1160, 
            1376, 520, 850, 787, 964, 1020, 1050, 517, 931, 728, 
            747, 1101, 1053, 797, 554, 700, 517, 773, 666, 761, 716, 429]

mayMidTempCases = [0, 1307, 1008, 0, 0, 0, 1160, 0, 0, 
            1376, 0, 0, 787, 964, 0, 1050, 0, 931, 728, 
            747, 1101, 1053, 797, 0, 0, 0, 0, 0, 761, 716, 429] //on high temparature days

mayHighTempCases = [0, 0, 0, 0, 0, 0, 0, 0, 0, 
            0, 0, 0, 0, 0, 1020, 0, 517, 0, 0, 
            0, 0, 0, 0, 554, 700, 517, 773, 666, 761, 716, 429] //on mid temparature days    

mayLowTempCases = [1540, 0, 0, 913, 975, 1022, 0, 1352, 1160, 
            0, 520, 850, 0, 0, 0, 0, 0, 0, 0, 
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] //on low temparature days           

novCases = [2815, 3648, 3236, 2580, 4562, 4322, 4098, 6023,
            5834, 4395, 4647, 6241, 5721, 6486, 6881, 7028, 
            5874, 6541, 6462, 6365, 6956, 7427, 8362, 6883,
            5144, 5584, 6956, 8654, 11268, 5000]

novHighTempCases = [0, 0, 3236, 2580, 4562, 4322, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 
            0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0]

novMidTempCases = [2815, 3648, 0, 0, 0, 0, 4098, 6023,
            0, 0, 4647, 0, 0, 0, 6881, 7028, 
            5874, 6541, 0, 0, 0, 7427, 8362, 6883,
            0, 5584, 0, 0, 0, 0]

novLowTempCases = [0, 0, 0, 0, 0, 0, 0, 0,
            0, 4395, 0, 6241, 5721, 6486, 0, 0, 
            0, 0, 6462, 0, 6956, 0, 0, 0,
            5144, 0, 6956, 8654, 11268, 5000]


function preload() {
    cloud = loadImage('https://i.imgur.com/MsvLwqH.png');   
    snowFlake = loadImage('https://i.imgur.com/wvzYocn.png');
    sun = loadImage('https://i.imgur.com/AGRTqDm.png');
}


function setup() {

    //star-size
    let SWH1 = random(2, 8);
    let SWH2 = random(6, 10);
    let SWH3 = random(10, 13);


    background(51,59,68);
    createCanvas(1300, 900);

    button = createButton("☀️");
    button.mousePressed();
    button.position(1180, 90);
    button.size(50,50);
    button.style('font-size', '25px');


    button = createButton("☁️");
    button.mousePressed();
    button.position(1180, 160);
    button.size(50,50);
    button.style('font-size', '25px');

    button = createButton("❄️");
    button.mousePressed();
    button.position(1180, 230);
    button.size(50,50);
    button.style('font-size', '25px');

    

    
         

}

function draw() {
    background(51,59,68);
    fill(255);
    textSize(12);
    text ('M A Y  :  C O V I D   C A S E S', 50, 80);
    text ('N O V E M B E R  :  C O V I D   C A S E S', 50, 780);

    textSize(21);
    text ('D o    C O V I D    C a s e s    I n c r e a s e    W h e n    T e m p ar a t u r e s    L o w e r  ?', 50, 840, 900, 60);
    strokeWeight(3.2);
    fill(255,10);
    noStroke();

    rect(50,80,width-200,320);
    rect(50,450,width-200,320);
    
    translate(30,50);

    fill(255, 80);
    may();

    fill(255,0,0,80);
    november();
    
    calendar();

    //sunrays();
    rainfall();

    noStroke();
    
    fill(255);
    //mayHigh();

    mousePressed();


    fill(255,10);

    rect(1137, 27, 60, 60);
    rect(1137, 97, 60, 60);
    rect(1137, 167, 60, 60);




  
}


function calendar() {
  fill(51,59,68);
  for (let i=0;i<31;i++) {
      let index = i + 1;
      //stroke(255, 50);
      
      push();
      fill(255);
      noStroke();
      textSize(12);
      text(index, i*(245/7)+38, 380);
      pop();
    }

}


    


 //____////____////____////____////____////____////____////____////____////____////____////____//   

function createSnowflake() {
    // create a random number of snowflakes each frame
    let t = frameCount / 60; // update time

    for (let i = 0; i < random(5); i++) {
        fill(255);
        snowflakes.push(new snowflake()); // append snowflake object
    }

    // loop through snowflakes with a for..of loop
    for (let flake of snowflakes) {
       flake.update(t); // update snowflake position
       flake.display(); // draw snowflake
    }
}

function snowflake() {
  //referenced from the p5.js open source examples
  // initialize coordinates
  this.posX = 0;
  this.posY = random(-50, 0);
  this.initialangle = random(0, 2 * PI);
  this.size = random(2, 5);

  // radius of snowflake spiral
  // chosen so the snowflakes are uniformly spread out in area
  this.radius = sqrt(random(pow(width / 2, 2)));

  this.update = function(time) {
    // x position follows a circle
    let w = 0.6; // angular speed
    let angle = w * time + this.initialangle;
    this.posX = width / 2 + this.radius * sin(angle);

    // different size snowflakes fall at slightly different y speeds
    this.posY += pow(this.size, 0.5);

    // delete snowflake if past end of screen
    if (this.posY > height) {
      let index = snowflakes.indexOf(this);
      snowflakes.splice(index, 1);
    }
  };

  this.display = function() {
    ellipse(this.posX, this.posY, this.size);
  }
}

//____////____////____////____////____////____////____////____////____//


function createRain() {
    // create a random number of snowflakes each frame
    let t = frameCount / 60; // update time

    for (let i = 0; i < random(5); i++) {
        fill(255);
        rain.push(new rainfall()); // append snowflake object
    }

    // loop through snowflakes with a for..of loop
    for (let drop of rain) {
       drop.update(t); // update snowflake position
       drop.display(); // draw snowflake
    }
}

function rainfall() {
  this.posX = 10;
  this.posY = random(0, width);
  this.initialangle = random(0, PI);
  this.size = random(4, 20);

  // radius of snowflake spiral
  // chosen so the snowflakes are uniformly spread out in area
  this.radius = sqrt(random(0,1000), 1);

  this.update = function(time) {
    // x position follows a circle
    let w = 1; // angular speed
    let angle = w * time + this.initialangle;
    this.posX = width / 35 + 1000 * sin(angle); // change this angle for rain

    // different size snowflakes fall at slightly different y speeds
    this.posY += pow(this.size, 5);

    // delete snowflake if past end of screen
    if (this.posY > 260) {
      let index = rain.indexOf(this);
      rain.shift(index, 3);
    }
  }

  this.display = function() {
    ellipse(this.posX, this.posY, this.size);
  }
}

//____////____////____////____////____////____////____////____////____////____//

function sunrays() {


  rays = random(280, 650);
 
  //stars in the universe
  fill(250, 200, 0);
  ellipse(mouseX*1.1, mouseY*1.8, random(2, 8), random(2, 8));
  ellipse(mouseX*1.3, mouseY*2.5, random(6, 10), random(6, 10));
  ellipse(mouseX*2.3, mouseY*1.5, random(10, 13), random(10, 13));
  ellipse(mouseX/1.1, mouseY/1.8, random(2, 8), random(2, 8));
  ellipse(mouseX/1.3, mouseY/2.5, random(6, 10), random(6, 10));
  ellipse(mouseX/2.3, mouseY/1.5, random(10, 13), random(10, 13));
  
  //glow
  fill(200, 130, 10, 20);
  ellipse(0, 0, (frameCount % 500)*2, (frameCount % 500)*2);
  ellipse(0, 0, (frameCount % 500)*4, (frameCount % 500)*4);
  ellipse(0, 0, (frameCount % 500)*8, (frameCount % 500)*8);
  ellipse(0, 0, (frameCount % 500)*16, (frameCount % 500)*16);
  ellipse(0, 0, (frameCount % 500)*24, (frameCount % 500)*24);
  
  //sun
  fill(250, 200, 0);
  ellipse(5, -11, rays - 20, rays - 30);

}







function may() {
    for (var i=0; i <= mayCases.length; i++) {
        fill(255, 99);
        rect((i*35+3)+25,350,33,-mayCases[i]*0.035);
        //ellipse((i*35+3)+25,190,-mayCases[i]*0.035);
    }
    if (mayCases[i]*0.25 >= 20) {
        fill(255, 99);
    }

}

function mayHigh() {
    for (var i=0; i <= mayHighTempCases.length; i++) {
        fill(255,99);
        rect((i*35+3)+25,350,33,-mayHighTempCases[i]*0.035);
    }
    if (mayHighTempCases[i]*0.25 >= 20) {
        fill(255,0,0,99);
    }
}

function mayMid() {
    for (var i=0; i <= mayMidTempCases.length; i++) {
        fill(255,99);
        rect((i*35+3)+25,350,33,-mayMidTempCases[i]*0.035);
    }
    if (mayMidTempCases[i]*0.25 >= 20) {
        fill(255,99);
    }
}

function mayLow() {
    for (var i=0; i <= mayLowTempCases.length; i++) {
        fill(255,99);
        rect((i*35+3)+25,350,33,-mayLowTempCases[i]*0.035);
    }
    if (mayLowTempCases[i]*0.25 >= 20) {
        fill(255,0,0,99);
    }
}



function november() {
    for (var i=0; i <= novCases.length; i++) {
        rect((i*35+3)+25,400,33,novCases[i]*0.035);
        //ellipse((i*35+3)+25,560,-novCases[i]*0.035);
    }
}

function novLow() {
    for (var i=0; i <= novLowTempCases.length; i++) {
        fill(255,0,0,99);
        rect((i*35+3)+25,400,33,novLowTempCases[i]*0.035);
        //ellipse((i*35+3)+25,560,-novCases[i]*0.035);
    }
    if (novLowTempCases[i]*0.25 >= 20) {
        fill(255,0,0,99);
    }
}

function novMid() {
    for (var i=0; i <= novMidTempCases.length; i++) {
        fill(255,0,0,99)
        rect((i*35+3)+25,400,33,novMidTempCases[i]*0.035);
        //ellipse((i*35+3)+25,560,-novCases[i]*0.035);
    }
    if (novMidTempCases[i]*0.25 >= 20) {
        fill(255,0,0,99);
    }
}

function novHigh() {
    for (var i=0; i <= novHighTempCases.length; i++) {
        fill(255,0,0,99);
        rect((i*35+3)+25,400,33,novHighTempCases[i]*0.035);
        //ellipse((i*35+3)+25,560,-novCases[i]*0.035);
    }
    if (novHighTempCases[i]*0.25 >= 20) {
        fill(255,0,0,99);
    }
}


function mousePressed() {
  //rect(1137, 27, 60, 60);
  //rect(1137, 97, 60, 60);
  //rect(1137, 167, 60, 60);
  if (mouseX >= 1137 && mouseX <= 1197 && mouseY >= 40 && mouseY <= 110) {
    mayHigh();
    novHigh();
    sunrays();
    
  } else if (mouseX >= 1137 && mouseX <= 1197 && mouseY >= 110 && mouseY <= 180) {
    mayMid();
    novMid();
    createRain();
  } else if (mouseX >= 1137 && mouseX <= 1197 && mouseY >= 200 && mouseY <= 250) {
    mayLow();
    novLow();
    createSnowflake();

}
}

Final Project

sketchDownload
 /*
Rachel Kim
Section C
rachelki@andrew.cmu.edu

Nicholas Wong 
Section A 
nwong1@andrew.cmu.edu
*/


//Every function has a comment before it showing who did the majority of the code: Nick, Rachel, or both of us.
//For functions that we did together, specific blocks, statements, and expressions are commented to show who did them.

//Player properties
var gravity = 0.4;
var defaultSpeed = 2;
var jumpForce = 10;
var constantSpeed = 2;
var playerStartPos = 300;
var walkImage = [];

//Stage properties
var stagePos = 0;
var stageSpeed = 2;

//Game state properties
var points = 0;
var gameOver = false;
var startGame = false;

//Game object lists
var platforms = [];
var covids = [];


//Background object lists
var backgroundBuildings = [];
var backgroundObjects = [];
var clouds = [];

//Building images
var housesA;
var housesB;
var supermarket;

//Background images
var cloud;
var sky;
var ground;

//Misc Images
var lampPost;
var streetSign;
var covidImage;


 //Preload images - Rachel Kim
function preload(){
 
    // These URLs are for the individual walk cycle images,
    var filenames = [];
    filenames[0] = "https://i.imgur.com/URNRJvg.png";
    filenames[1] = "https://i.imgur.com/dt8xXHQ.png";
    filenames[2] = "https://i.imgur.com/jmhE5QQ.png";
    filenames[3] = "https://i.imgur.com/twdsSdv.png";
    filenames[4] = "https://i.imgur.com/HWf5XmA.png";
    filenames[5] = "https://i.imgur.com/45onU9z.png";
    filenames[6] = "https://i.imgur.com/ey2SDeI.png";
    filenames[7] = "https://i.imgur.com/cG56PdF.png";
    filenames[8] = "https://i.imgur.com/533xGwE.png";
 
    for (var i = 0; i < filenames.length; i++) 
    {
    	walkImage[i] = loadImage(filenames[i]);
    }

    //loading images for use

    //Background elements
    lampPost = loadImage("https://i.imgur.com/zEDU732.png");
    streetSign = loadImage("https://i.imgur.com/TJ9H37E.png");
    housesA = loadImage("https://i.imgur.com/cwlJyQN.png");
    housesB = loadImage("https://i.imgur.com/lmhZBn8.png");
    supermarket = loadImage("https://i.imgur.com/Q0iAh9M.png");

    //Further background elements
    cloud = loadImage("https://i.imgur.com/4SgU4y8.png");
    sky = loadImage("https://i.imgur.com/34BWtmE.png");
    ground = loadImage("https://i.imgur.com/qLiqpgd.png");


    //Covid obstacles
    covidImage = loadImage("https://i.imgur.com/eJskXy6.png");
}

//Setup Function - Both Rachel and Nick
function setup()
{
	createCanvas(600, 400);
	rectMode(CENTER);
	textAlign(CENTER);
	translate(width/2,height/2)

	pl1 = new createPlayer(50,250,0); //Create a new player at (50,250) - Nick Wong


	//Unless otherwise noted, everything within the dashed lines was done by Rachel Kim:
	//---------------------------------------------------------------------------------------------------------

	//Create buildings
	for (let i = 0; i < 60; i++)
	{
		backgroundBuildings.push(createBuildings(500*i, 120, round(random(0,2))));
	}

	//Create street items
	for (let i = 0; i < 100; i++)
	{
		backgroundObjects.push(createStreetItems(400*i, 335, round(random(0,1))))
	}

	//Create clouds
	for(let i = 0; i < 50; i++)
	{
		clouds.push(createClouds(500*i, random(100,0), random(0,1)));
	}

	//Create platforms
	for (let i = 0; i < 100; i++)
	{
		var colour = color(random(50,150),150,random(50,150));
		platforms.push(createPlatform(100*i + 300, random(100,290), random(50,120), random(20,15), colour));
	}

	//Create covid obstacles
	for (let i = 0; i < 100; i++)
	{
		covids.push(createCovid(random(350,750)*i + 800, random(150,275)));
	}

	//-----------------------------------------------------------------------------------------------------------
	// ***Note***
	// The reason why we are not procedurally generating objects on the fly
	// as the screen scrolls and instead instantiating everything in setup
	// is because it messes with collision detection sometimes.
}

//Main update function - Both Rachel And Nick
function draw()
{
	//Background sky and ground - Rachel Kim
	image(sky, 0, 0, width, height)
	image(ground, 0 , 240, width, height/2);

	//Point calculation and display - Nick Wong
	points = round(-stagePos/10);
	textSize(14);
	text("Points: " + points.toString(), 35,25);

	//Unless otherwise noted, everything within the dashed lines was done by Nick Wong:
	//------------------------------------------------------------------------------------------------------------
	if(!gameOver & startGame)
	{
		push();
		stagePos -= defaultSpeed; //Set scroll speed to default speed
		translate(stagePos + playerStartPos,0); //Translate entire canvas by scroll speed

		drawBackground(); //Draw background - by Rachel Kim


		pl1.update(); //Update player
		pl1.display(); //Update player display

		//Update canvas display
		for(let i = 0; i < platforms.length; i++)
		{
			platforms[i].display();
		}

		//Update covid obstacle display
		for(let i = 0; i < covids.length; i++)
		{
			covids[i].display();
		}
		pop();

		//Increase scroll and movement speed if total points is a multiple of 300
		if(points % 300 == 0 & points > 0)
		{
			defaultSpeed += 0.5;
			constantSpeed += 0.5;
		}
	}
	//---------------------------------------------------------------------------------------------------------------
	//Game over screen - Rachel Kim
	else if(gameOver)
	{
		push();
		translate(width/2, height/2);
		textSize(32);
		fill(0);
		text("Game Over!", 10,0); 
		textSize(18);
		text("You scored " + points.toString() + " points!", 10,30);
		text("Press [Space] to restart");
		pop();
	}
	//Start game screen (only shows up once) - Nick Wong
	else if(!startGame)
	{
		push();
		translate(width/2, height/2);
		textSize(32);
		fill(0);
		text("Press [Space] to Start", 10,0);
		pop();
	}
	
}


//Draw background elements - Rachel Kim
function drawBackground()
{
	//Loop through and draw clouds
	for (let i = 0; i < clouds.length; i++)
	{
		clouds[i].display();
		clouds[i].update();
	}
	//Loop through and draw buildings
	for (let i = 0; i < backgroundBuildings.length; i++)
	{
		backgroundBuildings[i].display();
	}
	//Loop through and draw signs and lamps
	for (let i = 0; i< backgroundObjects.length; i++)
	{
		backgroundObjects[i].display();
	}

	//Draw ground
	push();
	fill(141,156,141);
	noStroke();
	rectMode(CORNERS);
	rect(-width, height - 100, width*100, height);
	pop();
}

//Animate player character - Rachel Kim
function drawPlayer() //Loop through walk images
{
	//Loop through at 1/5 speed
	if (frameCount % 5 == 0)
	{
		this.index++
	}

	//Reset image when it reaches end of list
	if(this.index >= 7)
	{
		this.index = 0;
	}

	image(walkImage[this.index],this.x,this.y - this.height/2,this.width,this.height)
}

//Update player - Both Rachel and Nick
function updatePlayer()
{	
	//Game over if player falls off stage - By Rachel Kim
	if(this.x <= -stagePos - playerStartPos)
	{
		gameOver = true;
	}

	//Game over if player touches a covid particle - By Nick Wong
	for(let i = 0; i < covids.length; i++)
	{
		if(this.x + this.width/2 >= covids[i].x - covids[i].width/2 & this.x - this.width/2 <= covids[i].x + covids[i].width/2 && 
			this.y + this.height/2 >= covids[i].y - covids[i].height/2 && this.y - this.height/2 <= covids[i].y + covids[i].height/2)
		{
			gameOver = true;
		}
	}

	//Unless otherwise noted, everything within the dashed lines was done by Nick Wong:
	//-------------------------------------------------------------------------------------------------------------------------------------------

	this.y += this.dy; // Add y velocity to y position

	//Check if player is on ground (not platforms)
	if(this.y > height - 100 - this.height/2)
	{
		//Set y velocity to 0 and y position to top of ground rect
		this.dy = 0;
		this.y = height - 100 - this.height/2;
		this.grounded = true;
	}
	else
	{
		this.grounded = false;
	}
	

	//Calculate x speed
	let previousLoc = this.x //Store previous x position
	this.x += constantSpeed; //Add speed
	let currentLoc = this.x //Store current x position
	this.dx = currentLoc - previousLoc; //The difference between previous and current is dx

	//Check platform collisions (still a bit buggy)
	for(let i = 0; i < platforms.length; i++)
	{
		//Check boundary of player is colliding with boundary of platform
		if(this.x + this.width/2 >= platforms[i].x - platforms[i].w/2 & this.x - this.width/2 <= platforms[i].x + platforms[i].w/2)
		{

			//Check boundary of player is colliding with boundary of platform
			if(this.y + this.height/2 > platforms[i].y - platforms[i].h/2 && this.y - this.height/2 < platforms[i].y + platforms[i].h/2)
			{
				//Check if colliding with side of platform
				if(this.dx > 0 && this.dy == 0)
				{
					constantSpeed = 0;
				}

				//Check if below platform
				if(this.dy < 0) //If player is traveling up, player touch bottom of platform
				{
					if(this.y - this.height/2 > platforms[i].y)
					{
						this.y = platforms[i].y + platforms[i].h/2 + this.height/2 + 2; //Set position to bottom of platform
						this.dy = 0 //Y speed to 0
					}

				}
				//Check if on top of platform
				if(this.dy > 0) //If player is traveling down, player touch top of platform
				{
					if(this.y + this.height/2 < platforms[i].y)
					{
						this.y = platforms[i].y - platforms[i].h/2 - this.height/2 + 2; //Set position to top of platform
						this.dy = 0; //Set Y speed to 0
						this.onPlatform = true; //On platform is true (can jump)

					}

				}

			}
			else
			{
				this.onPlatform = false //On platform is not true if not colliding
				constantSpeed = defaultSpeed; //Set player speed to default
			}
			
		}
	}
	this.dy += gravity; //Add gravity
	//-------------------------------------------------------------------------------------------------------------------------------------------
}

//Create player - Nick Wong
function createPlayer(px,py,pdy)
{
	var player = {x: px, y: py, dx: 0, dy: pdy, width: 25, height:45, grounded: false, onPlatform: false, index: 0, display: drawPlayer, update: updatePlayer}

	return player;
}


//Create platform - Nick Wong
function createPlatform(px,py,pw,ph,colour)
{
	var platform = {x: px, y: py, w: pw, h: ph, colour: colour, display: drawPlatform}

	return platform;
}

//Draw platform - Nick Wong
function drawPlatform()
{
	push();
	noStroke();
	fill(this.colour);
	rectMode(CENTER);
	rect(this.x, this.y, this.w, this.h);
	pop();
}

//Create Covid obstacle - Nick Wong
function createCovid(cx, cy)
{
	var cvd = {x: cx, y: cy, width: 20, height: 20, display: drawCovid}
	return cvd;
}

//Create Covid obstacle - Nick Wong
function drawCovid(cx, cy)
{
	push();
	image(covidImage, this.x, this.y, this.width, this.height);
	pop();
}

//Create buildings - Rachel Kim
function createBuildings(bx, by, i)
{
	var bdg = {x: bx, y: by, index: i, display: drawBuilding}
	return bdg;
}

//Render buildings - Rachel Kim
function drawBuilding()
{
	var buildings = [housesA, housesB, supermarket]
	image(buildings[this.index], this.x, this.y);
}

//Create lamps and signs - Rachel Kim
function createStreetItems(bx, by, i)
{
	var items = {x: bx, y: by, index: i, display: drawStreetItems}
	return items;
}

//Render lamps and signs - Rachel Kim
function drawStreetItems()
{
	push();
	scale(0.5,0.5); //Scale because too big
	var streetItems = [streetSign,lampPost]
	image(streetItems[this.index], this.x, this.y);
	pop();
}

//Create clouds - Rachel Kim
function createClouds(bx, by, s)
{
	var cld = {x: bx, y: by, speed: s, display: drawCloud, update: updateCloud}
	return cld
}

//Render clouds - Rachel Kim
function drawCloud()
{
	image(cloud, this.x, this.y);
}

//Add speed to clouds - Nick Wong
function updateCloud()
{
	this.x -= this.speed;
}

//Reset game by setting all values and lists to default - Nick Wong
function resetGame()
{
	covids = [];
	platforms = [];
	clouds = [];
	backgroundBuildings = [];
	streetItems = [];
	stagePos = 0;
	defaultSpeed = 2;
	constantSpeed = 2;
	setup();
	startGame = true;
	gameOver = false;
}

//Spacebar input - Both Rachel and Nick
function keyPressed()
{
	//Spacebar is pressed
	if(keyIsDown(32))
	{
		//Check if not in air - Nick Wong
		if(pl1.grounded || pl1.onPlatform)
		{
			pl1.dy -= jumpForce; //Jump if player is not in the air
		}

		//Reset game if game over - Rachel Kim
		if(gameOver)
		{
			resetGame();
		}

		//Start game if first time opening - Rachel Kim
		if(!startGame)
		{
			resetGame();
		}

	}
}




To run this program, simply press space.

This game is a side-scrolling platform game, where the screen constantly scrolls and the player can only jump.
The goal of the game is to not touch any covid particles and to not fall of the edge of the screen. The longer you survive, the faster the screen scrolls.

We created a side-scrolling game because we thought it would be fun. The theme was around Covid to stay relevant. A side-scrolling game proved to be somewhat challenging due to the dynamic collision detection. Checking bounds and making particles bounce off of things were covered in class, however it was a little harder to implement that in a game where we needed to know exactly where the player collided with an object, and how to deal with positioning the player during/after the collision. Due to time constraints, we did not have much time to play-test the game. For example, we realized only after implementing the graphical elements that the game was pretty hard to read; the player and covid obstacles constantly blended in with the background, making it hard to see where everything was.

Overall, if we had more time, we would have refined the collision detection system and added in an actual algorithm for creating obstacles and platforms, as currently they are being randomly generated and do not take into account whether it is possible to ‘beat’ or ‘pass’ any given set of platforms or obstacles. Also, we would implement sound.

Done by Rachel Kim and Nicholas Wong.

Final Project

This game is about “Trowing out flammable objects” like cigarettes, sparklers, fireworks, lanterns, heaters, and etc. With this game, I would be able to inform people to throw away caution objects, instead of leaving them in the forest.

*Systems & Keys

For this game, I have two scoring systems. One system is adding points(+)when the user successfully throws out an item while another system is deducting points(-) when the user throws out an item that is not dangerous.

Right arrow, Left arrow, ENTER (detailed instructions in the program)

*Goal

Score at least 5 points by throwing out flammable objects

*Attention

If you score lower than -5, Fail page will pop up. If you fail, you can’t start again because you CAN NOT undo wildfire 🙁 But you can start again if you success by pressing ENTER key 🙂

sketch copy
//Final Project

var introPage; //Click page
var introScreen; //click screen 
var item_counter = 0;
var item_interval = 13; // items amount decreases as the user earns more point
var item_startPage; // How page
var item_finishPage; // Congrats page
var item_finishFailPage;  //fail page
var item_startScreen; // How page illustration 
var item_finishScreen; //Congrats page illustration
var item_finishFailScreen; //Fail page illustration
var weapons = [];  //dangerous items array
var nonWeaps = []; //non-weapons array
var dropping_weapons = [] 
var dropping_nonWeaps = []
var trashcan; // trash can image
var backg;
var rate = 2; // speed of items falling
var item_score = 0; // score of throwing out items
var x = 0;
var height = 540;
var y = height - 100;

//trash can keys
var moveRight = false;
var moveLeft = false;

function preload() { // preloads images of dangerous weapons
    var Weapons = [
      "https://i.imgur.com/nu43pvX.png", //lantern
      "https://i.imgur.com/iftAnZO.png", //cigarette
      "https://i.imgur.com/JWyEvWW.png", //firework
      "https://i.imgur.com/RDVdcYb.png"]; //sparklers
    for (var i = 0; i < Weapons.length; i++){
      weapons.push(loadImage(Weapons[i]));
    }
    var NonWeaps = [
      "https://i.imgur.com/y3uSh1k.png", //leaf
      "https://i.imgur.com/RVbYaC6.png", //branch
      "https://i.imgur.com/2UQizyS.png"]; //acorn
    for (var i = 0; i < NonWeaps.length; i++){
      nonWeaps.push(loadImage(NonWeaps[i]));
    }
}

function item_setup () {
  createCanvas(450, 440);
  item_score = 0;
  item_startPage = false; 
  item_finishPage = false;
  trashcan = loadImage("https://i.imgur.com/JpPvsJn.png"); //trash can image
  item_startScreen = loadImage("https://i.imgur.com/in44Atu.png"); // How page of the game
  backg = loadImage("https://i.imgur.com/m6iJCVQ.png"); // forest background
  item_finishScreen = loadImage("https://i.imgur.com/UJUGvtS.png"); // congrats page of the game
  item_finishFailScreen = loadImage("https://i.imgur.com/JZkuboH.png");  //Fail page of the game
  item_counter = 0; // counts the number of trash caught in the trash can
  item_interval = 50;
}

function item_keyPressed() { 
  item_startPage =false;
  if (key === RIGHT){
    moveRight = true;
  } else if(key === LEFT){
    moveLeft = true;
  }
  if (item_startPage) {  // starts the game after pressing any key
      item_startPage = false;
  } else if (keyCode == ENTER) { // returns back to home screen 
      setup();
  }
}

function item_draw() { // draws other functions that is needed for game page
    if (item_startPage == true) {
      push();
      scale(1/4);
      image(item_startScreen, 0, 0);
      pop();
    } else {
      scale(0.35);
      image(backg, 0, 0);
      scale(1/0.4);
      drawTrashCan(); // draw trash can
      drawItems(); // draw dangerous items
      drawNonWeaps();    
      item_drawScore(); // number of items thrown out
      item_update(); // drops items continuously
    }
    if (item_finishPage == true) { // appears the finish page as the game ends
      push();
      scale(0.28);
      image(item_finishScreen,0,0);
      pop();
    }
    if (item_finishFailPage == true){
      push();
      scale(0.28);
      image(item_finishFailScreen,0,0);
      pop();
    }
}

function ScoreMax() { // if score of 5(maximum) is reached, shows congratulation page
    max = 5;          
    if(item_score >= max){
      item_finishPage = true;
    }
}

function ScoreMin(){  // if score of -5(minimum) is reached, shows Fail page
    min = -5;
    if(item_score <= min){
      item_finishFailPage = true;
    }
}

function item_drawScore() { // score on top left of the screen
  textSize(15);
  fill(25,30,37);
  text(("Your score: " + this.item_score), 10, 30);
}

function makeNonWeap(xposs, yposs, imagee) {
  var non = {
    "x": xposs,
    "y": yposs,
    "img": imagee,
    }
  return non;
}

function makeItem(xx, yy, image) {
  var item = {
    "x": xx,
    "y": yy,
    "img": image,
    }
  return item;
}

function drawNonWeaps() { 
    for (var i = 0; i < dropping_nonWeaps.length; i++){
      var non = dropping_nonWeaps[i];
      image(non.img, non.x, non.y,50,50);
    }
}

function drawItems() { 
    for (var i = 0; i < dropping_weapons.length; i++){
      var item = dropping_weapons[i];
      image(item.img, item.x, item.y,50,50);
    }
}

function drawTrashCan() { // renders the trash can
  image(trashcan, this.x, this.y-90,120,180);
}

function updateNonWeapY() { // updates the varying dropping of the non weapons
  for (var i = 0; i < dropping_nonWeaps.length; i++){
    var non = dropping_nonWeaps[i];
    non.y += rate;
    if (non.y > height) { 
      dropping_nonWeaps.splice(i, 1);
    }
  }
}

function updateItemY() { 
  for (var i = 0; i < dropping_weapons.length; i++){
    var item = dropping_weapons[i];
    item.y += rate;
    if (item.y > height) { 
      dropping_weapons.splice(i, 1);
    }
  }
}

function itemHitsTrashCan(item) { // moment when dangerous items hit the trash can
  var hit = this.x < item.x + 10 & item.x < this.x + 80 - 20 & item.y > this.y - 110; 
  return hit;
}

function nonWeapHitsTrashCan(non) { // moment when non-weapon items hit the trash can
  var hitt = this.x < non.x + 10 & non.x < this.x + 80 - 20 & non.y > this.y - 110;
  return hitt;
}

function updateNonWeapHit() { // the non-weapons disappear when it hits the trash can
  for (var i = 0; i < dropping_nonWeaps.length; i++){
    var non = dropping_nonWeaps[i];
    if(nonWeapHitsTrashCan(non)) {
      dropping_nonWeaps.splice(i, 1);
      item_score -= 1; //score decreases 
    }
  }
}

function updateItemHit() { // dangerous items disappear when it hits the trash can
  for (var i = 0; i < dropping_weapons.length; i++){
    var item = dropping_weapons[i];
    if(itemHitsTrashCan(item)) {
      dropping_weapons.splice(i, 1);
      item_score++; //score increases
      item_interval += 1; 
    }
  }  
}

function item_update() { // update random items from the top
  if(item_counter % item_interval == 0){
    var new_item = makeItem(random(10, 440), -80, random(weapons)); 
    dropping_weapons.push(new_item);
    var new_non = makeNonWeap(random(9,430),-80, random(nonWeaps));
    dropping_nonWeaps.push(new_non);
    item_counter = item_counter % item_interval; 
  }
  if(keyIsDown(RIGHT_ARROW) & this.x < width - 10){  // right arrow moving the trash can
     this.x += rate;
   }
  if (keyIsDown(LEFT_ARROW) & this.x > -10){ // left arrow moving the trash can
     this.x -= rate;
  }
  item_counter++;
  updateItemY();
  updateNonWeapY();
  updateItemHit();
  updateNonWeapHit();
  ScoreMax();
  ScoreMin();
}

function setup() {
  createCanvas(450, 450);
  introPage = true; // intro page is "true" here because it should start with this
  score = 0; //initial score
  introScreen = loadImage("https://i.imgur.com/EWQ38kD.png"); // home screen
  item_setup(); // calls the item setup function to combine
}

function keyPressed(){
  if (item_startPage | item_finishPage){
    item_keyPressed();
  } else if(item_finishPage & key == ENTER){  //going back to start page
    setup();
  }
}

function draw() {
  if (introPage == true) { // draws the intro page
    push();
    scale(1/4);
    image(introScreen, 0, 0);
    pop();
  } else {
    item_draw(); // game page
  }
}

function mouseClicked() {
  var xx = mouseX;
  var yy = mouseY;
  if (introPage) {
    if (0 < xx & xx < width & 0 < yy & yy < height) { //click any part of the screen
      item_startPage = true; // start page shows up
      introPage = false; 
    }
  }
}

Final Project

Virus Run

For my final project, I have created a side-scrolling game in which the player takes on the role of a coronavirus particle. As obstacles such as masks and hand sanitizer fly from right to left, the player must use the space bar to make the virus “jump” and avoid these obstacles. The longer the user holds down the key, the higher the virus floats, until it reaches the max height. If any of the obstacles are touched, the game stops. The score is then calculated based on the frame count. I was inspired by the dinosaur game which people can play when trying to use google with no internet connection, and if I had more time, I would have liked to make it so that the longer the game goes on, the more obstacles there are and the faster they move.

Some Screenshots of what the full canvas looks like:


sketch
var imgV; // image of virus
var imgM; // image of mask obstacle
var imgHS; // image of hand sanitizer

var imgStart; // image for starting screen
var imgGO; // image for game over


var mask = []; // array for masks on ground level
var mx = 800 // x coord of mask

var handSan = []; // array for hand sanitizer flying overhead
var hsx = 800 // x coord of hand sanitizer

var virusX = 100; // permanent x position of virus
var virusY = 270; // starting y position of virus
var virusR = 70; // radius of virus
var virusDy = 0; // change in height of virus when jumping

var score = 0; //counts score based on frames

var start = true; // checks to see if starting page is showing

var hills = []; // making moving hills as a background element
var noiseParam = 0;
var noiseStep = 0.02;

function preload(){
    imgV = loadImage("https://i.imgur.com/k04oKtW.png");
    imgM = loadImage("https://i.imgur.com/v2CRQLt.png");
    imgHS = loadImage("https://i.imgur.com/iFAELeQ.png");
    imgGO = loadImage("https://i.imgur.com/ORHbmPV.png");
    imgStart = loadImage("https://i.imgur.com/OUL56Za.png");

}



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

    //making hills
    for(var i = 0; i <= width/5; i++){
        var n = noise(noiseParam);
        hills[i];
        var value = map(n, 0, 1, 0, height/2);
        hills.push(value);
        noiseParam += 0.5*noiseStep;
    }
}

function draw(){
    
    if (start == true){
    	startingPage();

    } else { 

        background(8, 6, 51); // dark blue background
        drawHills();
        fill(55, 0, 104); // purple floor
        rect(0, 370, 800, 30);
        image(imgV, virusX, virusY, 107, 100); // image of virus
    
        if(keyIsDown(32)){ 
            virusY -= 10;
            // while the space bar is down, the virus moves upward
        } else if (virusY < 270){ 
            virusY +=10;
            // when the space bar is let go while the virus is in the air, 
            //the virus moves down
        } else { virusY = 270; } 
            // otherwise, the virus stays on the ground
        if (virusY < 40)
        { virusY += 10}

        createNewMask();
        displayMask();

        createNewHandSan();
        displayHandSan();

        checkIfGameOver();
    
        score += 1; 

        //display score count in the top right corner during the game
        textSize(15);
        fill(190, 215, 62);
        text(score, 745, 40);
        
    }
    
}

function startingPage(){ // starting page with instructions
	push();
	fill(8, 6, 51);
	rect(-1, -1, 801, 801);
	fill(190, 215, 62);
	textSize(25);
	text('Press any key to begin >', 487, 365);
	textSize(15);
	text('Use the space bar to avoid obstacles!', 490, 230);
	pop();

	image(imgStart, 40, 80, 700, 100);
	image(imgM, 540, 250, 60, 58);
	image(imgHS, 620, 247, 62, 70);
	image(imgV, virusX, virusY, 107, 100);
	

}

function keyPressed(){ 
	if(start == true){ start = false; } // game begins
	
}

//drawing hills (background element)
function drawHills(){
	push();
    translate(0, 130)
    hills.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height/2);
    hills.push(value);
    // draws shape for sand
    beginShape();
    vertex(0, height);
    for(var i = 0; i <= width/5; i++){
        //filling the hill color
        fill(255, 255, 255, 10);
        noStroke();
        //vertex function to fill the hills
        vertex((i * 5), hills[i]); 
        vertex((i + 1) * 5, hills[i + 1]);   
    }
    vertex(width, height);
    endShape(CLOSE);
    pop();
}


function checkIfGameOver (){

	for (i = 0;i < mask.length;i++)
    {
        if ((dist(mask[i].x, 400,  virusX, 400) <= virusR) 
            // tests if the mask comes within a certain distance of the virus
             & virusY == 270){

            gameOver(); // the screen goes darker
            noLoop(); // the game stops
        }
    }

	for (i = 0;i < handSan.length;i++){
        if ((dist(handSan[i].x, handSan[i].y,  virusX, virusY) <= virusR)){ 
            //tests if the hand sanitizer comes within a certain distance of the virus


            gameOver(); // the screen goes darker
            noLoop(); // the game stops
        }
    }
}


// BEGIN CODE FOR MASK OBSTACLES



function displayMask(){ // update mask positions and display them
    for(var i = 0; i < mask.length; i++){
        mask[i].move();
        mask[i].draw();
    }
}

function createNewMask(){ 
// makes new masks with some random probability
    if(random(0, 1) < 0.008){
        mask.push(makeMask(800));
    }
}

function moveMask(){
    this.x -= 10;
}

function drawMask(){
    mask.push();
    image(imgM, this.x, this.y, 60, 60); 
}

// function to make mask obstacle object
function makeMask(){
    var m = {x: mx, 
             y: 310,
             move: moveMask,
             draw: drawMask
        }
    return m;
}

// BEGIN CODE FOR HAND SANITIZER OBSTACLES

function displayHandSan(){ // update hand sanitizer positions and display them
    for(var i = 0; i < handSan.length; i++){
        handSan[i].move();
        handSan[i].draw();
    }
}

function createNewHandSan(){ 
// makes new masks with some random probability
    if(random(0, 1) < 0.005){
        handSan.push(makeHandSan(800));
    }
}

function moveHandSan(){
    this.x -= 10;
}

function drawHandSan(){
    handSan.push();
    image(imgHS, this.x, this.y, 80, 90); 
}

// function to make mask obstacle object
function makeHandSan(){
    var h = {x: hsx, 
             y: random(30, 100),
             move: moveHandSan,
             draw: drawHandSan
        }
    return h;
}


function gameOver(){
// screen displayed when the virus hits an obstacle
    push();
    fill(0, 0, 0, 80);
    rect(0, 0, 800, 400);
    pop();

    image(imgGO, 50, 100, 700, 100);    
   
    push();
    fill(190, 215, 62);
    noStroke();
    textSize(20);
    text('SCORE:' + ' ' + score, 340, 250);
    textSize(15);
    text('Refresh to play again!', 340, 280)
    pop();
}


Final Project- COVID-19 cases in America

My final project is an infographic of America with the number of COVID-19 cases in each state. Based on the number of cases in America, and how high the number is, the color of each state varies from a medium pink to a very dark red.

My process and code is very long because I planned out my steps wrong and had the wrong approach. I thought if I separated each state, I would be able to let mouseX and mouseY detect each state. However, because the pngs are the same size, my approach did not work out.

sketch
//Chris Han
//Final Project
//15-104 Section C

var California;
var Alabama;
var Arizona;
var Arkansas;
var Colorado;
var Connecticut;
var Delaware;
var Florida;
var Georgia;
var Idaho;
var Illinois;
var Indiana;
var Iowa;
var Kansas;
var Kentucky;
var Louisiana;
var Maine;
var Maryland;
var Massachussets;
var Michigan;
var Mississippi;
var Minnesota;
var Montana;
var Nebraska;
var Nevada;
var NewJersey;
var NewMexico;
var NewYork;
var NorthCarolina;
var Ohio;
var NorthDakota;
var Oklahoma;
var Oregon;
var Pennsylvania;
var Virginia;
var Washington;
var WestVirginia;
var RhodeIsland;
var SouthCarolina;
var SouthDakota; 
var Tennessee;
var Texas;
var Vermont;
var Utah;
var Wisconsin;
var Wyoming;
var Missouri;
var NewHampshire;

function preload(){
	California = loadImage("https://i.imgur.com/M90B6i6.png");
	Alabama = loadImage("https://i.imgur.com/A0rMfn9.png");
	Arizona = loadImage("https://i.imgur.com/FZgFQXG.png");
	Arkansas = loadImage("https://i.imgur.com/mady7aS.png");
	Colorado = loadImage("https://i.imgur.com/Cm0XtJk.png");
	Connecticut = loadImage("https://i.imgur.com/Kgbe7x6.png");
	Delaware = loadImage("https://i.imgur.com/gPJn6me.png");
	Florida = loadImage("https://i.imgur.com/hH4ByDe.png");
	Georgia = loadImage("https://i.imgur.com/QqS08V1.png");
	Idaho = loadImage("https://i.imgur.com/IAWMdLX.png");
	Illinois = loadImage("https://i.imgur.com/dFEAfM3.png");
	Indiana = loadImage("https://i.imgur.com/yINwRlF.png");
	Iowa = loadImage("https://i.imgur.com/bDpW2F1.png");
	Kansas = loadImage("https://i.imgur.com/viHxihJ.png");
	Kentucky = loadImage("https://i.imgur.com/dYri9KS.png");
	Louisiana = loadImage("https://i.imgur.com/fmCBz3P.png");
	Maine = loadImage("https://i.imgur.com/MLwg0xh.png");
	Maryland = loadImage("https://i.imgur.com/GR8e2uJ.png");
	Massachussets = loadImage("https://i.imgur.com/llu4pfW.png");
	Michigan = loadImage("https://i.imgur.com/Dzu9Anc.png");
	Mississippi = loadImage("https://i.imgur.com/HRFksTw.png");
	Minnesota = loadImage("https://i.imgur.com/PQ2rbnn.png");
	Montana = loadImage("https://i.imgur.com/FFZVEDr.png");
	Nebraska = loadImage("https://i.imgur.com/pjSdpc4.png");
	Nevada = loadImage("https://i.imgur.com/gKE4OD7.png");
	NewJersey = loadImage("https://i.imgur.com/pLxSZQ6.png");
	NewMexico = loadImage("https://i.imgur.com/ZxZ5TGy.png");
	NewYork = loadImage("https://i.imgur.com/fOMfdss.png");
	NorthCarolina = loadImage("https://i.imgur.com/ml7w2CO.png");
	Ohio = loadImage("https://i.imgur.com/P6npxwO.png");
	NorthDakota = loadImage("https://i.imgur.com/IHceHrO.png");
	Oklahoma = loadImage("https://i.imgur.com/YUe8N4U.png");
	Oregon = loadImage("https://i.imgur.com/lKD2lzT.png");
	Pennsylvania = loadImage("https://i.imgur.com/q8BZJJY.png");
	Virginia = loadImage("https://i.imgur.com/xXbl27h.png");
	Washington = loadImage("https://i.imgur.com/iYUxkXx.png");
	WestVirginia = loadImage("https://i.imgur.com/opvQBQx.png");
	RhodeIsland = loadImage("https://i.imgur.com/Eqyjeyw.png");
	SouthCarolina = loadImage("https://i.imgur.com/n7mnprl.png");
	SouthDakota = loadImage("https://i.imgur.com/0dnuWnc.png");
	Tennessee = loadImage("https://i.imgur.com/fA9Ey2X.png");
	Texas = loadImage("https://i.imgur.com/N3H2oM5.png");
	Vermont = loadImage("https://i.imgur.com/VKAgM5K.png");
	Utah = loadImage("https://i.imgur.com/HsGInYv.png");
	Wisconsin = loadImage("https://i.imgur.com/1706iC4.png");
	Wyoming = loadImage("https://i.imgur.com/P2FMqfi.png");
	NewHampshire = loadImage("https://i.imgur.com/JUHRFya.png");
	Missouri = loadImage("https://i.imgur.com/KtNPgmC.png");


}

function setup() {
    createCanvas(600,400);
    //background('white');
    background('white');
}


function draw() {
	textSize(10);
    fill('black');
    text('COVID-19 cases in America', 250, 70);
    textSize(7);
    text('click on any state to start',270, 85);

	California.resize( 400,400);
	image(California, 0,0);

	Alabama.resize( 400,400);
	image(Alabama, 0, 0);

	Arizona.resize( 400,400);
	image(Arizona, 0, 0);

	Arkansas.resize( 400, 400);
	image(Arkansas, 0 , 0);

	Colorado.resize( 400, 400);
	image(Colorado, 0, 0);

	Connecticut.resize( 400, 400);
	image(Connecticut, 0, 0);

	Delaware.resize(400, 400);
	image(Delaware, 0,0);

	Florida.resize(400, 400);
	image(Florida, 0, 0);

	Georgia.resize(400, 400);
	image(Georgia, 0, 0);

	Idaho.resize(400, 400);
	image(Idaho, 0, 0);

	Illinois.resize(400, 400);
	image(Illinois, 0, 0);

	Indiana.resize(400, 400);
	image(Indiana, 0, 0);

	Iowa.resize(400, 400);
	image(Iowa, 0, 0);

	Kansas.resize(400,400);
	image(Kansas, 0, 0);

	Kentucky.resize(400,400);
	image(Kentucky, 0, 0);

	Louisiana.resize(400,400);
	image(Louisiana, 0, 0);

	Maine.resize(400,400);
	image(Maine, 0, 0);

	Maryland.resize(400,400);
	image(Maryland, 0, 0);

	Massachussets.resize(400,400);
	image(Massachussets, 0, 0);

	Michigan.resize(400,400);
	image(Michigan, 0, 0);

	Mississippi.resize(400,400);
	image(Mississippi, 0, 0);

	Minnesota.resize(400,400);
	image(Minnesota, 0, 0);

	Montana.resize(400,400);
	image(Montana, 0, 0);

	Nebraska.resize(400,400);
	image(Nebraska, 0, 0);

	Nevada.resize(400,400);
	image(Nevada, 0, 0);

	NewJersey.resize(400,400);
	image(NewJersey, 0, 0);

	NewMexico.resize(400,400);
	image(NewMexico, 0, 0);

	NewYork.resize(400,400);
	image(NewYork, 0, 0);

	NorthCarolina.resize(400,400);
	image(NorthCarolina, 0, 0);

	Ohio.resize(400,400);
	image(Ohio, 0, 0);

	NorthDakota.resize(400,400);
	image(NorthDakota, 0, 0);

	Oklahoma.resize(400,400);
	image(Oklahoma, 0, 0);

	Oregon.resize(400,400);
	image(Oregon, 0, 0);

	Pennsylvania.resize(400,400);
	image(Pennsylvania, 0, 0);

	Virginia.resize(400,400);
	image(Virginia, 0, 0);

	Washington.resize(400,400);
	image(Washington, 0, 0);

	WestVirginia.resize(400,400);
	image(WestVirginia, 0, 0);

	RhodeIsland.resize(400,400);
	image(RhodeIsland, 0, 0);

	SouthCarolina.resize(400,400);
	image(SouthCarolina, 0, 0);

	Tennessee.resize(400,400);
	image(Tennessee, 0, 0);

	Texas.resize(400,400);
	image(Texas, 0, 0);

	Vermont.resize(400,400);
	image(Vermont, 0, 0);

	Utah.resize(400,400);
	image(Utah, 0, 0);

	Wisconsin.resize(400,400);
	image(Wisconsin, 0, 0);

	Wyoming.resize(400,400);
	image(Wyoming, 0, 0);

	SouthDakota.resize(400,400);
	image(SouthDakota, 0, 0);

	NewHampshire.resize(400,400);
	image(NewHampshire, 0, 0);

	Missouri.resize(400,400);
	image(Missouri, 0, 0);

	mouseClicked();

}


function mouseClicked(){

	//CALIFORNIA

		if (mouseX > 40 & mouseX < 65 && mouseY > 115 && mouseY < 235) {
		textSize(5);
		fill('white');
		text('CA, 1.49M', 45, 170);
	}

	//nevada
	if(mouseX > 59 & mouseX < 102 && mouseY > 126 && mouseY < 211){
		textSize(5);
		fill('white');
		text('NV, 179K', 70, 160);
	}

	//oregon
	if(mouseX > 41 & mouseX < 84 && mouseY < 126 && mouseY > 86){
        textSize(5);
		fill('white');
		text('OR, 89K', 70, 104);
	}
	//washington
	if( mouseY > 49 & mouseY < 94 && mouseX < 95 && mouseX > 62 ){
		textSize(5);
		fill('white');
		text('WA, 201K', 70, 75);
	}

	//idaho
	if (mouseX > 92 & mouseX < 111 && mouseY > 64 && mouseY < 140){
		textSize(5);
		fill('white');
		text('ID, 118K', 95, 123);
	}
	//utah
	if( mouseX > 93 & mouseX < 126 && mouseY > 143 && mouseY < 199){
		textSize(5);
		fill('white');
		text('utah lol', 102, 176);
	}
	//arizona
	if( mouseX > 81 & mouseX < 119 && mouseY > 198 && mouseY < 262){
		textSize(5);
		fill('white');
		text('AZ, 390K', 90, 221);
	}

	//montana
	if ( mouseX > 110 & mouseX < 170 && mouseY > 72 && mouseY < 120){
		textSize(5);
		fill('white');
		text('MT, 71K', 127, 92);

	}

	//wyoming
	if ( mouseX > 121 & mouseX < 165 && mouseY > 119 && mouseY < 164){
		textSize(5);
		fill('white');
		text('WY, 38K', 133, 142);

	}

	//colorado

	if ( mouseX > 129 & mouseX < 173 && mouseY > 166 && mouseY < 209){
		textSize(5);
		fill('white');
		text('CO, 283K ', 136, 187);
	}

	//new mexico
	if (mouseX > 118 & mouseX < 160 && mouseY > 209 && mouseY < 262){
		textSize(5);
		fill('white');
		text('NM, 117K', 127, 235);
	}

	//north dakota
	if (mouseX > 174 & mouseX < 212 && mouseY > 87 && mouseY < 119){
	    textSize(5);
		fill('white');
		text('ND, 87K ', 179, 101);

	}

	//south dakota
	if ( mouseX > 168 & mouseX < 212 && mouseY > 120 && mouseY < 152){
		textSize(5);
		fill('white');
		text('SD, 89K', 176, 134);

	}

	//nebraska
	if ( mouseX > 165 & mouseX < 211 && mouseY > 153 && mouseY < 185){
		textSize(5);
		fill('white');
		text('NE, 147K', 173, 159);
	}

	//kansas
	if ( mouseX > 173 & mouseX < 219 && mouseY > 186 && mouseY < 218){
		textSize(5);
		fill('white');
		text('KS, 188K', 179, 198);
	}

	//oklahoma
	if ( mouseX > 182 & mouseX < 220 && mouseY > 217 && mouseY < 254 ){
		textSize(5);
		fill('white');
		text('OK, 229K', 187, 231);
	}
	//texas
	if ( mouseX > 160 & mouseX < 220 && mouseY > 250 && mouseY < 338){
		textSize(5);
		fill('white');
		text('TX, 1.42M', 174, 274);
	}

	//minnesota
	if (mouseX > 212 & mouseX < 237 && mouseY > 92 && mouseY < 150){
		textSize(5);
		fill('white');
		text('MN, 371K', 220, 112);
	}

	//iowa
	if (mouseX > 213 & mouseX < 243 && mouseY > 150 && mouseY < 181){
		textSize(5);
		fill('white');
		text('IA, 254K ', 220, 164);
	}

	//missouri
	if (mouseX > 220 & mouseX < 246 && mouseY > 183 && mouseY < 226){
		textSize(5);
		fill('white');
		text('MO, 355K ', 226, 207);
	}

	//arkansas
	if (mouseX > 219 & mouseX < 246 && mouseY > 227 && mouseY < 264){
		textSize(5);
		fill('white');
		text('AR, 182K', 226, 244);
	}

	//louisiana
	if( mouseX > 226 & mouseX < 240 && mouseY > 265 && mouseY < 302){
		textSize(5);
		fill('white');
		text('LA, 264K ', 229, 277);
	}

	//wisconin
	if(mouseX > 236 & mouseX < 265 && mouseY > 118 && mouseY < 161){
		textSize(5);
		fill('white');
		text('WI, 461K', 243, 133);
	}
	//illinois
	if(mouseX > 242 & mouseX < 266 && mouseY > 162 && mouseY < 218){
		textSize(5);
		fill('white');
		text('IL, 835K', 249, 188);
	}

	//kentucky
	if( mouseX > 256 & mouseX < 302 && mouseY > 207 && mouseY < 222){
		textSize(5);
		fill('white');
		text('KY, 221K', 272, 215);
	}

	//tennessee
	if(mouseX > 254 & mouseX < 296 && mouseY > 222 && mouseY < 241){
		textSize(5);
		fill('white');
		text('TN, 426K', 261, 233);
	}

	//Mississippi
	if(mouseX > 244 & mouseX < 263 && mouseY > 243 && mouseY < 287){
		textSize(5);
		fill('white');
		text('MS, 175K', 244, 263);
	}

	//michigan
	if(mouseX > 274 & mouseX < 296 && mouseY > 127 && mouseY < 166){
		textSize(5);
		fill('white');
		text('MI, 460K ', 276, 145);
	}

	//indiana
	if( mouseX > 267 & mouseX < 285 && mouseY > 168 && mouseY < 203){
		textSize(5);
		fill('white');
		text('IN, 415K', 270, 185);
	}
	//alabama
	if( mouseX > 263 & mouseX < 286 && mouseY > 243 && mouseY < 285){
		textSize(5);
		fill('white');
		text('AL, 289K', 270, 264);
	}
	//ohio
	if( mouseX > 285 & mouseX < 311 && mouseY > 169 && mouseY < 198){
		textSize(5);
		fill('white');
		text('OH, 542K', 289, 184);
	}

	//georgia
	if( mouseX > 286 & mouseX < 313 && mouseY > 242 && mouseY < 288){
		textSize(5);
		fill('white');
		text('GA, 513K', 293, 266);
	}
	//florida
	if( mouseX > 307 & mouseX < 327 && mouseY > 289 && mouseY < 346){
		textSize(5);
		fill('white');
		text('FL, 1.11M', 309, 311);
	}
	//west virginia
	if (mouseX > 299 & mouseX < 322 && mouseY > 186 && mouseY < 216){
		textSize(5);
		fill('white');
		text('WV, 60K', 303, 200);
	}

	//virginia
	if (mouseX > 299 & mouseX < 343 && mouseY > 196 && mouseY < 219){
		textSize(5);
		fill('white');
		text('VA, 274K', 318, 209);
	}

	//north carolina
	if (mouseX > 299 & mouseX < 347 && mouseY > 220 && mouseY < 241){
		textSize(5);
		fill('white');
		text('NC, 425K', 312, 230);
	}

	//south carolina
	if (mouseX > 303 & mouseX < 334 && mouseY > 239 && mouseY < 265){
		textSize(5);
		fill('white');
		text('SC, 245K', 306, 245);
	}

	//pennylvania
	if (mouseX > 311 & mouseX < 345 && mouseY > 158 && mouseY < 182){
		textSize(5);
		fill('white');
		text('PA, 276K', 319, 169);
	}

	//new jersey
	if (mouseX > 347 & mouseX < 356 && mouseY > 164 && mouseY < 190){
		textSize(5);
		fill('white');
		text('NJ, 392K', 350, 173);
	}
	//maryland
	if (mouseX > 329 & mouseX < 342 && mouseY > 184 && mouseY <200){
		textSize(5);
		fill('white');
		text('MA, 280K', 356, 147);
	}

	//delaware
	if( mouseX > 345 & mouseX < 353 && mouseY > 186 && mouseY < 195){
		textSize(5);
		fill('white');
		text('DE, 476K', 347, 189);
	}

	//newyork
	if( mouseX > 317 & mouseX < 355 && mouseY >123 && mouseY < 156){
		textSize(5);
		fill('white');
		text('NY, 760K', 325, 149);
	}
	//conneticut
	if( mouseX > 356 & mouseX < 365 && mouseY > 152 && mouseY < 163){
		textSize(5);
		fill('white');
		text('CT, 147K', 359, 162);
	}

	//rhode island
	if( mouseX > 365 & mouseX < 370 && mouseY > 150 && mouseY < 158){
		textSize(5);
		fill('white');
		text('RI, 70K ', 371, 158);
	}
	//massachusetts
	if(mouseX > 355 & mouseY < 372 && mouseY > 144 && mouseY < 150){
		textSize(5);
		fill('white');
		text('MA, 280K', 368, 142);
	}

	//vermont
	if( mouseX > 351 & mouseX < 360 && mouseY > 121 && mouseY < 145){
		textSize(5);
		fill('white');
		text('VT, 5K', 351, 125);
	}

	//new hampshire
	if(mouseX > 359 & mouseX < 368 && mouseY > 117 && mouseY < 143){
		textSize(5);
		fill('white');
		text('NH, 29K', 362, 136);
	}
	//maine
	if(mouseX > 364 & mouseX < 388 && mouseY > 91 && mouseY < 128){
		textSize(5);
		fill('white');
		text('ME, 15K', 365, 106);
	}




}




Final Project

For my final project, I created an animation. My animation tells a story about myself and how I personally am affected by the pandemic. I believe my story will resonate with a lot of students. My animation highlights the unseen effects that COVID has had on students and shows the progressive loss of motivation and the effects on mental health.
The animation runs without user interaction; however, if the user clicks the mouse, a text box appears describing the current state of the pandemic in a quick “news flash”

covidanimationDownload
//Flora Xia Section B

var sR = 157; //sky red component
var sG = 196; //sky green component
var sB = 245; //sky blue component
var sRC = .5;
var sGC = .5;
var sBC = .5;
//original positions for mask
var mX = 112;
var mY = 340;
var mW = 300;
var mL = 150;
//change in 
var mdX = 1;
var mdY = 1;
var mdW = 1;
var mdL = 1;
//eyes
var eyeRLinks = [
    "https://i.imgur.com/yT0USca.png",
    "https://i.imgur.com/0LktvFO.png",
    "https://i.imgur.com/Dh0klJU.png",
    "https://i.imgur.com/n7e82Zj.png"]

var eyeLLinks = [
    "https://i.imgur.com/LzeqRqt.png",
    "https://i.imgur.com/dcffyk3.png",
    "https://i.imgur.com/UDx8Xmn.png",
    "https://i.imgur.com/WMngOhd.png"]

var eyeR;
var eyeL;

var eyeRImages = [];
var eyeLImages = [];
//details
var detailLinks = [
    "https://i.imgur.com/611Lsvj.png",
    "https://i.imgur.com/iBUjUeg.png",
    "https://i.imgur.com/1dlHNvm.png"]

var detail;
var detailImages = [];
//clouds
var clouds = []


function preload(){
	//eye images
	for (var i = 0; i < 4; i++){
		eyeRImages[i] = loadImage(eyeRLinks[i]);
		eyeLImages[i] = loadImage(eyeLLinks[i]);
	}
	eyeR = eyeRImages[0];
	eyeL = eyeLImages[0];
	for (var j = 0; j < 3; j++){
		detailImages[j] = loadImage(detailLinks[j]);
	}
	detail = detailImages[0];
}


function setup() {
    createCanvas(510, 600);
    frameRate(5);
    for (var i = 0; i < 2; i++){
    	var rx = random(width);
    	var ry = random(20, 200);
    	clouds[i] = makeCloud(rx, ry);
    }
}

function draw() {
	background(sR, sG, sB);
	skyGrey();
	face();
	eyes();
	maskLaptop();
	details();
	updateCloud();
	removeCloud();
	addCloud();
	if (frameCount > 125){
		appleLogo();
	}
	print(frameCount);
}

function mousePressed(){
	let m1 = 'BREAKING NEWS : COVID-19';
	let m2 = 'NEWS: COVID-19 Gets Worse';
	let m3 = 'NEWS: Cases Rising';
	let m4 = 'NEWS: Second Peak';
	fill(255, 150);
	rect(0, 260, 500, 50);
	fill(255, 0, 0);
	textSize(35);
	if (frameCount <= 50){
		text(m1, 0, 300);
	}else if (frameCount > 50 & frameCount <= 100){
		text(m2, 0, 300);
	}else if (frameCount > 100){
		text(m3, 0, 300);
	}

}

function eyes(){
	if (frameCount <= 50){
		//normal eyes
		eyeR = eyeRImages[0];
		eyeL = eyeLImages[0];
	}else if (frameCount > 50 & frameCount <= 100){
		//eyes w eyebags
		eyeR = eyeRImages[1];
		eyeL = eyeLImages[1];
	}else if (frameCount > 100 & frameCount <= 150){
		//eyes tearing
		eyeR = eyeRImages[2];
		eyeL = eyeLImages[2];
	}else if (frameCount > 150){
		//crying
		eyeR = eyeRImages[3];
		eyeL = eyeLImages[3];
	}
	//position images
	image(eyeR, 285, 225, 130, 130);
	image(eyeL, 102, 225, 130, 130);
}

function details(){
	if (frameCount <= 50){
		//details mask
		detail = detailImages[0];
	}else if (frameCount > 50 & frameCount <= 75){
		//details hair
		detail = detailImages[1];
	}else if (frameCount > 75 & frameCount <= 100){
		//details hair
		detail = detailImages[2];
	}else if (frameCount > 100 & frameCount <= 125){
		detail = detailImages[1];
	}else if (frameCount > 125){
		detail = detailImages[2];
	}
	image(detail, 0, 0);
}

function skyGrey(){
	//color change
	sR -= sRC;
	sG -= sGC;
	sB -= sBC;
	if (sR == 134){
		sRC = 0;
	} 
	if (sG == 145) {
		sGC = 0;
	}
	if (sB == 158) {
		sBC = 0;
	}
	

}

function face(){
	//hair back
	noStroke();
	fill(74, 63, 47);
	rect(37, 220, 430, 400);
	//neck
	fill(190, 150, 110);
	rect(175, 450, 150, 120);
	//shirt
	fill(245, 235, 244);
	ellipse(250, 570, 480, 60);
	rect(10, 570, 480, 60);
	fill(190, 150, 110);
	ellipse(250, 540, 150, 40);
	//face shape
	fill(194, 156, 118);
	ellipse(250, 300, 350, 420);
	eyebrows();
	//hair bangs left
	push();
	rotate(radians(30));
	fill(207, 201, 167);
	ellipse(200, 55, 150, 300);
	ellipse(245, 45, 70, 175)
	fill(74, 63, 47);
	ellipse(190, 55, 150, 300);
	ellipse(235, 45, 70, 175)
	pop();
	//hair bangs right
	push();
	rotate(radians(330));
	fill(207, 201, 167);
	ellipse(245, 315, 150, 300);
	ellipse(185, 250, 70, 175);
	fill(74, 63, 47)
	ellipse(250, 315, 150, 300);
	ellipse(190, 250, 70, 175);
	pop();
	//hair bangs top
	fill(74, 63, 47);
	ellipse(250, 50, 250, 100);
	//ears
	fill(194, 165, 125);
	ellipse(60, 290, 40, 80);
	//earrings
	fill(222, 210, 140);
	circle(60, 320, 10);
	circle(50, 310, 7);
	//nose
	nose();
}

function eyebrows(){
	fill(82, 64, 33, 150);
	rect(300, 225, 50, 15);
	rect(150, 225, 50, 15);
	fill(82, 64, 33, 50);
	rect(295, 225, 50, 15);
	rect(155, 225, 50 ,15);
	rect(290, 225, 50, 15);
	rect(160, 225, 50, 15);
}

function nose(){
	fill(163, 130, 96, 150);
	ellipse(260, 385, 50, 15);
	stroke(163, 130, 96, 150);
	strokeWeight(3);
	arc(275, 340, 10, 50, (PI / 2), (PI / 2) * 3);
}

function maskLaptop(){
	if (frameCount < 50){
		//mask
		fill(140, 196, 212);
	    stroke(255);
	    strokeWeight(3);
	    //masklines
	    //earloops
	}
	if (frameCount >= 50){
		//turning into laptop
	    mX -= mdX;
	    mY += mdY;
	    mW += mdW;
	    mL += mdL;
	    fill(140, 196, 210);
	    if (mX == 60){
		    mdX = 0
		    fill(150, 190, 200);
	    }
	    if (mY == 400){
		    mdY = 0
		    fill(161, 185, 190);
	    }
	    if (mW == 375){
		    mdW = 0
		    fill(172, 185, 189)
	    }
	    if (mL == 210){
		    mdL = 0
		    fill(182, 185, 186);
		    //add mac symbol
	    }
	    strokeWeight(3);
	    stroke(255);
	}
	rect(mX, mY, mW, mL); 
}

function appleLogo(){
	fill(255);
	noStroke();
	circle(255, 530, 50);
	fill(182, 185, 186);
	circle(283, 528, 30);
	push();
	translate(255, 530);
	rotate(radians(30));
	fill(255)
	ellipse(-15, -40, 5, 20);
	pop();
}

//cloud object
function updateCloud(){
    for (var i = 0; i < clouds.length; i ++){
        clouds[i].move();
        clouds[i].display();
    }
}

function removeCloud(){
    var keepClouds=[];
    for (var i = 0; i < clouds.length; i++) {
        if (clouds[i].x < width) {
            keepClouds.push(clouds[i]);
        }
    }
    clouds = keepClouds;
}

function addCloud(){
    //little probability
    var newCloudLikelihood = 0.007; 
    if (random(0,1) < newCloudLikelihood) {
        clouds.push(makeCloud(15, 15));
    }
}

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

function displayCloud(){
    fill(255);
    noStroke();
    push();
    translate(this.x, this.y - 20);
    circle(0, 0, 135);
    circle(-60, 10, 90);
    circle(60, 10, 90);
    fill(110);
    textSize(24);
    text('anxiety', -40 ,0);
    pop();
}

function makeCloud(birthLocationX, birthLocationY){
    var cloud = {x: birthLocationX,
                y:birthLocationY,
                speed:random(3, 7),
                move: moveCloud,
                display: displayCloud};
    return cloud;
}

Final Project – Polarization & Authoritarianism

I interpreted the 2020 theme as part of our ongoing political crisis. The Republican party has begun to show their true colors as authoritarians, so I tried to explain what that process means in this project using simple particle visualizations.

Users can learn some basic political science, and have fun screwing over democracy in the process.

For the most part, the project acts as a sort of slideshow, moving between animations. The last slide, however, allows users to manipulate the system directly for themselves. The particle simulation code we used extensively in class was used & heavily modified for this simulation. The program also relies heavily on for-loops, objects, and if-statements.

-Robert

sketch
var slide = 0;  //variable that keeps track of which slide is being displayed. 0 corresponds to the title screen.

var democrat    //these four are color variables, used to keep track of each type of voter
var rep
var auth    //authoritarians
var orange  //orange represents 'the strongman leader'.
var voters  //'neutral', or persuadable voters

var vPart = []; //particle array representing "generic" voters
var dPart = []; //particle array representing democrat voters
var rPart = []; //particle array representing republican voters
var aPart = []; //particle array representing authoritarian voters
var dict = [];

//hard boundaries are on by default for all particles so that they can be put in boxes.

function createVParticles(n, x, y, w, h, v) {   //creates voters given a quantity n, position range defined by x, y, w, & h, and a velocity range -v to v
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(vPart, newP);
    }
}

function createDParticles(n, x, y, w, h, v) {   //creates democrat particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(dPart, newP);
    }
}

function createRParticles(n, x, y, w, h, v) {   //creates republican particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(rPart, newP);
    }
}

function createAParticles(n, x, y, w, h, v) {   //creates authoritarian particles within a given rectangle & velocity range
    for(i=0; i<n; i++) {
        newP = makeParticle(random(x, x+w), random(y, y+h), random(-v, v), random(-v, v));
        newP.bHardBoundaries = true;
        append(aPart, newP);
    }
}

function makeDictator(x, y, d) {    //makes a dynamic orange circle
    var d = {tx: x, ty: y, diameter: d, force: 1, drawFunction: drawDictator};

    dict[0] = d;
}

function drawDictator() {   //draws the circle, maps it to the mouse
    var left = this.tx - this.diameter/2;
    var right = this.tx + this.diameter/2;
    var top = this.ty - this.diameter/2;
    var bottom = this.ty + this.diameter/2;

        this.tx = mouseX;
        this.ty = mouseY;

    push();
    noStroke();
    fill(orange);
    circle(this.tx, this.ty, this.diameter);
    pop();
}

function setup() {
    createCanvas(950, 500);   //multiplication is used to keep the canvas the same w/h ratio as the american flag. This setup is 950 x 500
    background(255);+
    text("p5.js vers 0.9.0 test.", 10, 15);
    frameRate(60);

    dem = color(70, 70, 240);
    rep = color(240, 70, 70);
    auth = color(25);   
    voter = color(200);
    orange = color(255, 140, 25);

    noStroke();
}

var count = 0;  //used to make stuff move

function draw() {
    if (slide == 0) {   //title screen. Each slide is coded separately here, and simply clicking will advance the slide.
        push();
            background(255);
            if (count < width/64) { //displays the moving title screen intro, then the interactive title screen
                titleIntro();
            } else {
                titleScreen();
            }
        pop();
    }

    if (slide == 1) {   //Explainer screen, explains the diagrams, what the particles mean, and gives context
        push();
            background(65);

            push();
            rectMode(CENTER);
            textAlign(CENTER, CENTER);
            textSize(30);
            fill(255);
            text('These particles represent voters. Each color represents a political leaning, and each box represents a grouping.',width/2, 100, width/2, 300);
            
            textStyle(BOLD);    //labels for each voter box
            textSize(25);
            fill(dem);
            text('Liberal', 157.5, 400);

            fill(rep)
            text('Conservative', 367.5, 400);

            fill(voter);
            text('Moderate', 577.5, 400);

            fill(auth);
            text('Authoritarian', 787.5, 400);
            pop();            

            for(i=0; i < dPart.length; i++) {   //these for loops update the position of each particle & draws them
                dPart[i].draw(dem, 15);         //dems
                dPart[i].update(105*1, 250, 105, 105);
            }  
            for(i=0; i < rPart.length; i++) {   //reps
                rPart[i].draw(rep, 15);
                rPart[i].update(105*3, 250, 105, 105);
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);
                vPart[i].update(105*5, 250, 105, 105);
            }
            for(i=0; i < aPart.length; i++) {   //authoritarians
                aPart[i].draw(auth, 15);
                aPart[i].update(105*7, 250, 105, 105);
            }

            noStroke();
            stroke(255);
            strokeWeight(10);
            noFill();
            for(i=1; i<=7; i+=2) {
                rect(105*i-10, 250-10, 105+20, 105+20);
            }
        pop();
        slideOut(); //slideOut creates a fade-in transition for the slide. It needs to be put last so that it can fade in ON TOP of everything else.
    }

    if (slide == 2) {   //Geographic polarization, civil war thru WWII
        push();
            background(65);
            push();
                fill(255);
                textAlign(CENTER, CENTER);
                textSize(30);
                text('Since before the civil war through the 60s, Americans are divided sharply by geography & slavery. Regional loyalties are strong, and the glacial pace of information keeps regions separate.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Republican (North)', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Democrat (South)', 750, 235, 150, 200);
            pop();

            for(i=0; i < dPart.length; i++) {   //these for loops update the position of each particle & draws them
                dPart[i].draw(dem, 15);         //dems
                if(i < dPart.length/2) {
                    dPart[i].update(225, 250, 200, 200);    //because there are two boxes with the same kind of voter
                } else {                                    //doing updates has to be divided in half
                    dPart[i].update(525, 250, 200, 200);
                }
            }  
            for(i=0; i < rPart.length; i++) {   //reps
                rPart[i].draw(rep, 15);
                if(i < rPart.length/2) {
                    rPart[i].update(225, 250, 200, 200);
                } else {
                    rPart[i].update(525, 250, 200, 200);
                }
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);
                if(i < vPart.length/2) {
                    vPart[i].update(225, 250, 200, 200);
                } else {
                    vPart[i].update(525, 250, 200, 200);
                }
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                rect(525-10, 250-10, 200+20, 200+20);   //right rect
                rect(225-10, 250-10, 200+20, 200+20);   //left rect
            pop();
        pop();
        slideOut();
    }

    if (slide == 3) {   //ideological consolidation, WWII thru 1990s.
        push();
            background(65);

            push();
                fill(255);
                textAlign(CENTER, CENTER);
                textSize(30);
                text('Later, mass media allowed disparate people to connect. Conservative Republicans & liberal Democrats consolidated, creating idealogically distinct parties - with fewer swing voters.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Democrat', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Republican', 750, 235, 150, 200);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps (now on the right)
                rPart[i].update(225, 250, 500, 200);
                rPart[i].vx += .015                              //slowly alters particle velocties so they fall to the right
                rPart[i].vx = constrain(rPart[i].vx, -2, 5)     //constrains their velocities so they stay generally on the right
            }  
            for(i=0; i < dPart.length; i++) {   //dems (now on the left)
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);
                dPart[i].vx -= .015                              //slowly fall to the left
                dPart[i].vx = constrain(dPart[i].vx, -5, 2)     //constrains to the left
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);       //swing voters float free
                vPart[i].update(225, 250, 500, 200);
            }
            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
        pop();
        
        slideOut();
    }

    if (slide == 4) {   //Something strange has happened recently
        background(65);
        push();
            for (i=0; i<9; i++) {
                for (j=0; j<9; j++) {
                    fill(auth);
                    circle(375+20*(j+1) + random(-2, 2), 250+20*(i+1) + random(-2, 2), 15); //Because these 'voters' are supposed to be in lockstep, I presented them here as circles instead of particles
                }   //it makes the code simpler
            }

            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('Recently, something strange has happened: the emergence of a new kind of voter. A minority of voters, mostly conservative, became afraid of losing power - and looked to strongman leaders.', 50, 50, 850, 150);
            pop();

            noFill();   //the authoritarian box (appropriately orange)
            stroke(255);
            strokeWeight(10);
            rect(375-10, 250-10, 200+20, 200+20);

            push();
                fill(orange);   //the 'leader' circle, whose location will act as an attractor point
                noStroke();
                ellipse(width/2, 350, 40, 40);

                fill(255);
                textAlign(LEFT, TOP);
                textSize(22);
                text('Authoritarians dont act like normal voters. What is most important to them is group loyalty. They value safety & order, and look for leaders that make them feel strong.', 650, 235, 250, 220);
            pop();
        pop();

        slideOut();
    }

    if (slide == 5) { //the authoritarian consolidation
        background(65);
        push();
            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('In 2016, authoritarian voters became activated in response to demographic change. They consolidated around a leader in the republican party, pushing out or converting other conservatives.', 50, 50, 850, 150);
            pop();

            push();
                textStyle(BOLD);

                fill(255);
                textAlign(RIGHT, TOP);
                textSize(25);
                text('Democrat', 50, 235, 150, 200);

                textAlign(LEFT, TOP);
                textSize(25);
                text('Republican', 750, 235, 150, 200);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps (now on the right)
                rPart[i].update(225, 250, 500, 200);
                rPart[i].vx += .01              //slowly alters particle velocties so they fall to the right
                if (rPart[i].px > 585) {        //if they go TOO FAR to the right, then they get pushed back
                    rPart[i].vx -= .5
                }                                               
                rPart[i].vx = constrain(rPart[i].vx, -2, 5)     //constrains their velocities so they stay generally on the right
            }  
            for(i=0; i < dPart.length; i++) {   //dems (now on the left)
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);
                dPart[i].vx -= .02                              //slowly fall to the left
                dPart[i].vx = constrain(dPart[i].vx, -5, 2)     //constrains to the left
            }
            for(i=0; i < vPart.length; i++) {   //swing voters
                vPart[i].draw(voter, 15);       //swing voters float free
                vPart[i].update(225, 250, 300, 200);

                if (vPart[i].px >= 585) {        //if they go TOO FAR to the right, then they get pushed back
                    vPart[i].vx -= .5
                }
                vPart[i].vx = constrain(rPart[i].vx, -2, 2)     //constrains their velocities so they don't go too fast
            }
            for(i=0; i < aPart.length; i++) {   //dems (now on the left)
                aPart[i].draw(auth, 15);
                aPart[i].update(600, 250, 125, 200);
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
        pop();
        slideOut();
    }

    if (slide == 6) { //authoritarian simulation
        background(65);
        push();
            push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(30);
                text('Even an otherwise stable political system can be disrupted by strongman demagogues.', 50, 50, 850, 150);

                //textStyle(BOLD);
                textSize(20);
                text('Move the mouse to disrupt democracy.', 50, 175, 850, 150);
            pop();

            for(i=0; i < rPart.length; i++) {   //these for loops update the position of each particle & draws them
                rPart[i].draw(rep, 15);         //reps are attracted to the dictator weakly
                rPart[i].update(225, 250, 500, 200);

                if (rPart[i].px > dict[0].tx) {rPart[i].vx -= .05}
                if (rPart[i].px < dict[0].tx) {rPart[i].vx += .05}
                if (rPart[i].py > dict[0].ty) {rPart[i].vy -= .05}
                if (rPart[i].py < dict[0].ty) {rPart[i].vy += .05}

                rPart[i].vx = constrain(rPart[i].vx, -5, 5);
                rPart[i].vy = constrain(rPart[i].vy, -5, 5);
            }  
            for(i=0; i < dPart.length; i++) {   //dems get pushed away by the circle strongly
                dPart[i].draw(dem, 15);
                dPart[i].update(225, 250, 500, 200);

                if (dPart[i].px > dict[0].tx) {dPart[i].vx += .2}
                if (dPart[i].px < dict[0].tx) {dPart[i].vx -= .2}
                if (dPart[i].py > dict[0].ty) {dPart[i].vy += .2}
                if (dPart[i].py < dict[0].ty) {dPart[i].vy -= .2}

                dPart[i].vx = constrain(dPart[i].vx, -5, 5);
                dPart[i].vy = constrain(dPart[i].vy, -5, 5);
            }
            for(i=0; i < vPart.length; i++) {   //swing voters get pushed away by the circle weakly
                vPart[i].draw(voter, 15);
                vPart[i].update(225, 250, 500, 200);

                if (vPart[i].px > dict[0].tx) {vPart[i].vx += .1}
                if (vPart[i].px < dict[0].tx) {vPart[i].vx -= .1}
                if (vPart[i].py > dict[0].ty) {vPart[i].vy += .1}
                if (vPart[i].py < dict[0].ty) {vPart[i].vy -= .1}

                vPart[i].vx = constrain(vPart[i].vx, -5, 5);
                vPart[i].vy = constrain(vPart[i].vy, -5, 5);
            }
            for(i=0; i < aPart.length; i++) {   //authoritarians move towards the circle strongly
                aPart[i].draw(auth, 15);
                aPart[i].update(225, 250, 500, 200);

                if (aPart[i].px > dict[0].tx) {aPart[i].vx -= .2}
                if (aPart[i].px < dict[0].tx) {aPart[i].vx += .2}
                if (aPart[i].py > dict[0].ty) {aPart[i].vy -= .2}
                if (aPart[i].py < dict[0].ty) {aPart[i].vy += .2}

                aPart[i].vx = constrain(aPart[i].vx, -5, 5);
                aPart[i].vy = constrain(aPart[i].vy, -5, 5);
            }

            push();
                noFill();
                stroke(255);
                strokeWeight(10);
                
                beginShape();   //left box
                    vertex(435, 240);
                    vertex(215, 240);
                    vertex(215, 460);
                    vertex(435, 460);
                endShape();

                beginShape();   //left box
                    vertex(515, 240);
                    vertex(735, 240);
                    vertex(735, 460);
                    vertex(515, 460);
                endShape();
            pop();
            dict[0].drawFunction();
        pop();
        slideOut();
    }

    if (slide == 7) {
        background(65);
        push();
                fill(255);
                textAlign(CENTER, TOP);
                textSize(20);
                text('- Benjamin Franklin', 50, 175, 850, 150);

                textSize(30);
                text('Thank You for Playing', 50, 350, 850, 150);


                textStyle(BOLD);
                textSize(30);
                text('“Those who would give up essential liberty to purchase a little temporary safety, deserve neither liberty nor safety.”', 50, 50, 850, 150);

        pop();
        slideOut();
    }

}

function titleIntro() { //Provides the introduction to the title screen, where the rectangles fly in
        push();
            fill(dem);
            rect(0, 0, count*32, height);
        pop();

        push();
            fill(rep);
            rect(width, 0, -count*32, height);
        pop();

        if(count < width/64) {
                count++
        }
}

function titleScreen() {    //Displays the title screen
    push();
        noStroke();
        fill(dem);
        rect(0, 0, width/2, height);
    pop();

    push();
        noStroke();
        fill(rep);
        rect(width/2, 0, width, height);
    pop();

    if (mouseX > width/2 & mouseY > 0 && mouseY < height) {
        push();
            fill(auth);
            rect(width/2, 0, constrain(mouseX-width/2-25, 0, width/2-25), height);
        pop();
        

        push();
            noStroke();
            fill(rep);
            textAlign(RIGHT, CENTER);
            textSize(40);
            text('POLARIZATION & AUTHORITARIANISM', (width/2 + constrain(mouseX-width/2-50, 0, width/2-25))/2, 0, constrain(mouseX, 0, width/2-25), height);
            textSize(10);
            text('CLICK TO PROCEED', (width/2 + constrain(mouseX-width/2-50, 0, width/2-45))/2, 60, constrain(mouseX, 0, width/2-25), height);
        pop();

        push();
            noStroke();
            fill(dem);
            rect(0, 0, width/2, height);
        pop();
    }   
}

function slideOut() {   //Runs on top of each slide, creating the illusion of a smooth fade-in
    push();
        fill(65, 255-count);
        rect(0, 0, width, height);
    pop();
    if (count <= 255) {
        count+=3
    }
}

function mousePressed() {   //advances which simulation is shown. Also used to instance functions which need to run exactly once for a slide.
    slide++


    vPart = []; //empties all the arrays whenever the slide changes, giving a fresh slate.
    dPart = [];
    rPart = [];
    aPart = [];
    dictator = [];
    count = 0;

    if (slide == 1) {
        createDParticles(1, 105*1, 250, 105, 105, 2);
        createRParticles(1, 105*3, 250, 105, 105, 2);
        createVParticles(1, 105*5, 250, 105, 105, 2);
        createAParticles(1, 105*7, 250, 105, 105, 2);
    }

    if (slide == 2) {
        createDParticles(5, 225, 250, 200, 200, 2);
        createRParticles(5, 225, 250, 200, 200, 2);
        createVParticles(5, 225, 250, 200, 200, 2);

        createDParticles(5, 525, 250, 200, 200, 2);
        createRParticles(5, 525, 250, 200, 200, 2);
        createVParticles(5, 525, 250, 200, 200, 2);
    }

    if (slide == 3) {
        createDParticles(6, 225, 250, 200, 200, 2);
        createRParticles(6, 225, 250, 200, 200, 2);
        createVParticles(3, 225, 250, 200, 200, 2);

        createDParticles(6, 525, 250, 200, 200, 2);
        createRParticles(6, 525, 250, 200, 200, 2);
        createVParticles(3, 525, 250, 200, 200, 2);
    }

    if (slide == 4) {
        //just a placeholder in case I wanted to put stuff here later
    }

    if (slide == 5) {
        createDParticles(10, 225, 250, 200, 200, 2);
        createRParticles(6, 585, 250, 140, 200, 2);

        createVParticles(4, 365, 250, 200, 200, 2);

        createAParticles(14, 585, 250, 140, 200, 5);
    }

    if (slide == 6) {
        createDParticles(10, 225, 250, 200, 200, 0);
        createRParticles(10, 525, 250, 200, 200, 0);

        createVParticles(10, 225, 250, 200, 200, 0);
        createAParticles(10, 525, 250, 200, 200, 0);

        makeDictator(width/2, height/2, 40);
    }


    if (slide > 7) {    //wraps the whole program around if the last slide is reached
        slide = 0;
    }
}

//start particle code [CODE BELOW IS MODIFIED FROM EARLIER EXAMPLES TO MAKE IT MORE GENERAL & FLEXIBLE]
function makeParticle(x, y, dx, dy) {
    var p = {px: x, py: y, vx: dx, vy: dy,
             bFixed: false,
             bLimitVelocities: false,
             bPeriodicBoundaries: false,
             bHardBoundaries: false,
             update: particleUpdate,
             handleBoundaries: particleHandleBoundaries,
             draw: particleDraw
            }
    return p;
}

// Update the position based on force and velocity. x, y, w, h define a rectangle within which the particle bounces around.
function particleUpdate(x, y, w, h) {
        this.handleBoundaries(x, y, w, h);
        this.px += this.vx;
        this.py += this.vy;
}

// do boundary processing if enabled. Modified to process bounds within a given rectangle instead of the canvas. x, y, w, h are passed off from te particleUpdate function
function particleHandleBoundaries(x, y, w, h) {
    if (this.bPeriodicBoundaries) {
        if (this.px > x + w) this.px -= width;
        if (this.px < x) this.px += width;
        if (this.py > y + h) this.py -= height;
        if (this.py < y) this.py += height;
    } else if (this.bHardBoundaries) {
        if (this.px >= x + w) {
            this.vx = -abs(this.vx);
        }
        if (this.px <= x) {
            this.vx = abs(this.vx);
        }
        if (this.py >= y + h) {
            this.vy = -abs(this.vy);
        }
        if (this.py <= y) {
            this.vy = abs(this.vy);
        }
    }
}

//Draws the particle, given a color & size
function particleDraw(c, s) {
    fill(c);
    ellipse(this.px, this.py, s, s);
}