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.

Project 11: Landscape

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

var rockForeground = []; //Rocks in foreground
var rockMidground = []; //Rocks in midground
var mountains = []; //Mountains in background

//Rock variables
var foregroundRockChance = 0.03; //Probability of rock spawn per frame
var midgroundRockChance = 0.03; //Probability of rock spawn per frame

//Mountain variables
var noiseParam = 1; //Noise param for mountain generation
var noiseStep = 0.01; //Noise step for mountain generation

//Sky variables
var offset = 23; //Wave offset

//Floor grid variables
var lineStart = []; //Line at horizon
var lineEnd = []; //Line at bottom of canvas

function setup() 
{
	frameRate(30);
    createCanvas(480, 300);

    //Initialize mountains
	for(let i = 0; i < width/4; i++)
	{
		var n = noise(noiseParam);
		mountains[i];
		var value = map(n, 0, 1, 0, height);
		mountains.push(value);
		noiseParam += noiseStep;
	}

	//Initialize Floor lines
	for(let i = 0; i<49; i++)
	{
		lineStart[i] = 10*i;
		lineEnd[i] = -1200 + (60*i);
	}

}

function draw() 
{

	background(255, 166, 200);

	//Draw sky wave
	drawSkyPattern();

	//Draw mountains
	drawMountains();

	//Draw floor
	drawFloor();

	//Draw floor lines
	drawFloorLines();


	//Color for rocks
	var foregroundColor = color(115, 31, 77);
	var midgroundColor = color(130, 57, 84);

	//Create rocks based on probability
	if(random(0,1) < foregroundRockChance)
	{
		rockForeground.push(createRock(width + 20,220 + random(0,20),20,random(20,30),foregroundColor)); //Rocks in foreground
	}
	else if (random(0,1) < midgroundRockChance)
	{
		rockMidground.push(createRock(width + 20, 190 + random(-20,20),10, 20, midgroundColor)); //Rocks in background
	}

	//Update positions
	updateMidgroundRocks();
	updateForegroundRocks();
}

//Draw wave
function drawSkyPattern()
{
	push();
	noFill();
	for(let w = 0; w <= height; w += 10) //Number of waves
    {       
        strokeWeight(1)
        stroke(255)

        //Create curvy lines
        beginShape();
		for(let x = 0; x < width; x++)
		{
		    let angle = offset + x *0.01;
		    let y = map(sin(angle), -1, 1, 0, 50);
		    vertex(x,y + w);
		}
		vertex(width,height);
		vertex(0,height);
		endShape();
    }
    pop();


}

//Draw mountains
function drawMountains()
{
	//Add and remove noise values to mountain list
	mountains.shift();
    var n = noise(noiseParam);
    var value = map(n, 0, 1, 0, height);
    noiseParam += noiseStep;
   	mountains.push(value);
	

	//Draw mountain shapes based on noise values
    beginShape();
    for(var i = 0; i <= width/4; i++)
    {
	    fill(224, 105, 149);
	    noStroke();
	    vertex((i * 6), mountains[i] - 50); 
	    vertex((i + 1) * 6, mountains[i + 1] - 50);   
	    vertex(300, 100000); 
    }
    endShape(CLOSE);

	//Draw mountain shapes based on noise values
    beginShape();
    for(var i = 0; i <= width/3; i++)
    {
	    fill(191, 86, 125);
	    noStroke();
	    vertex((i * 10), mountains[i]- 10); 
	    vertex((i + 1) * 10, mountains[i + 1] - 10);   
	    vertex(300, 100000); 
    }
    endShape(CLOSE);
}

//Update and cull rocks
function updateForegroundRocks()
{
	for(let i = 0; i < rockForeground.length; i++)
	{
		rockForeground[i].move();
		rockForeground[i].display();

		//Check to see if rocks are off canvas
		if(rockForeground[i].x + rockForeground[i].size < 0)
		{
			rockForeground.shift(); //Remove rock
		}
	}
}

//Update and cull rocks
function updateMidgroundRocks()
{
	//Check to 
	for(let i = 0; i < rockMidground.length; i++)
	{
		rockMidground[i].move();
		rockMidground[i].display();

		//Check to see if rocks are off canvas
		if(rockMidground[i].x + rockMidground[i].size < 0)
		{
			rockMidground.shift(); //Remove rock
		}
	}
}

//Draw floor lines
function drawFloorLines()
{
	push();
	for(let i = 0; i < 49; i++)
	{
		stroke(255, 148, 194);
		strokeWeight(1);

		//Draw line
		line(lineStart[i],170,lineEnd[i],height);

		//Move lines
		lineStart[i] -= 5;
		lineEnd[i] -= 30;

		//Reset lines if off canvas
		if(lineStart[i] == 0)
		{
			lineStart[i] = width;
		}
		if(lineEnd[i] == -1200)
		{
			lineEnd[i] = 1680;
		}
	}
	pop();
}

//Draw floor rectangle
function drawFloor()
{	
	push();
	noStroke();
	fill(158, 70, 102);
	rect(0,170,width,height);
	pop();
}



//Create rock
function createRock(xPos, yPos,rockSpeed, rockSize, rockColor, )
{
	var fRock = {x: xPos, 
				y: yPos,
				speed: rockSpeed * -1,
				sides: random(3,5),
				size: rockSize,
				color: rockColor,
				variation: random(0.5,1),
				move: rockMove,
				display: rockDisplay}
	return fRock;
}

function rockMove()
{
	this.x += this.speed; //Move the rock
}

function rockDisplay()
{
	//Change rock color
	fill(this.color);
	noStroke();

	//Create rock based on size, variation, and number of sides
	let angle = TWO_PI / this.sides;
	beginShape();
	for (let a = 0; a < TWO_PI; a += angle) 
	{
	let sx = this.x + cos(a * this.variation) * this.size;
	let sy = this.y + sin(a * this.variation) * this.size;
	vertex(sx, sy);
	}
	endShape(CLOSE);
}

A stylized desert. Rocks are objects that are randomly generated, and are automatically culled when off the canvas. Rocks further away from the bottom of the canvas move slower than rocks closer to the bottom of the canvas. Mountains vary in speed to give the illusion of depth.

Inspiration:

Mountains eps 10 background view pink Royalty Free Vector

Looking Outwards 11:

I’ve seen Angela Washko’s work before, and I find her exploration of feminism through interactive alternative video games. One such game I found interesting was The Game: The Game, a project that presents an exploration of consent and politics. The game is presented in the format of a dating simulator, where players experience the tactics and practices of male pick-up artists and “the seduction community”. These pick-up gurus attempt to seduce the player, providing and in-depth look into the specific social behaviors around dating, giving insight on the experiences many women have in the real world.

Angela Washko is a visiting assistant professor at Carnegie Mellon University, a small University in Pittsburgh, Pennsylvania (often mistaken for Central Michigan University). She was known for creating performances and “social stunts” in the game World Of Warcraft, where she discusses feminism and toxic masculinity in video games. Having attended a few of her classes, I find her style of critiquing patriarchal systems and toxic-masculinity online very amusing.

https://angelawashko.com/section/437138-The-Game-The-Game.html

Project 10: Sonic Story

sketchDownload
//Nicholas Wong
//Section A
//nwong1@andrew.cmu.edu
//Assignment 10

var angle = 0; //Angle for clock
var catEyes = 0; //Cat eye size
var mousePos = 0; //Mouse position
var mousedx = 5; //Mouse speed

function preload() 
{
    //For use in web upload
   catSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/cat.wav");
   mouseSound =loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/mouse1.wav"); 
   clockSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/clock.wav");
   thunderSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2020/wp-content/uploads/2020/11/thunder-2.wav"); 

    //For use in localhost
    /*
    catSound = loadSound("cat.wav");
    clockSound = loadSound("clock.wav");
    mouseSound = loadSound("mouse1.wav");
    thunderSound = loadSound("thunder.wav");
    */
}

function soundSetup() 
{ // setup for audio generation
    catSound.setVolume(0.5);
    mouseSound.setVolume(0.4);
    clockSound.setVolume(0.7);
    thunderSound.setVolume(1);
}

function setup() {
    // you can change the next 2 lines:
    createCanvas(480, 480);
    createDiv("p5.dom.js library is loaded.");
    useSound();
    frameRate(1);
    angleMode(DEGREES);
}




function draw() 
{
    background(140,90,50);

    //Backdrop (window, room)
    drawBackdrop();

    //Frame dependant events
    if(frameCount % 7 == 0)
    {
        clockSound.play();
    }

    if(frameCount % 12 == 0)
    {
        drawLightning() //Draw lightning for 1 frame
        catEyes = 6; //Cat eyes are wide open
        mousedx *= -1; //Mouse reverses direction
        thunderSound.play(); //Thunder sound
        catSound.play(); //Meow
    }


    //Window
    windowLines(95,200);
    windowLines(95,260);

    //Objects
    drawDrawer(330,height/2+100);
    drawPainting(400,270);
    drawClock(width/2 + 20,height/2);

    //Cat
    drawCat(340,310);

    //Mouse
    drawMouse(mousePos,430);



}

function drawCat(x,y)
{
    //Cat artwork
    push();
    noStroke();
    ellipseMode(CENTER);
    fill(40);
    ellipse(x+13,y+17,50,30);
    ellipse(x-2,y+25,17,15);
    ellipse(x+30,y+25,15,15);
    fill(40);
    ellipse(x,y,35,30);
    triangle(x-15,y-8,x-5,y-10,x-10,y-23)
    translate(18,0);
    triangle(x-15,y-8,x-5,y-10,x-10,y-23)
    fill(255)

    //Cat eyes
    ellipse(x-10,y,7,catEyes);
    ellipse(x-26,y,7,catEyes);
    pop();

    //Cats eyes decrease in size every frame
    catEyes -= 1;
    

    //Cat eyes minimum size is 1;
    if(catEyes <= 0)
    {
        catEyes = 1;
    }

}

function drawMouse(x,y)
{
    //Mouse artwork
    push();
    noStroke();
    ellipse(x,y,20,10);
    ellipse(x+8,y-3,4);
    triangle(x+5,y-4,x+15,y,x+5,y+4);
    stroke(255);
    strokeWeight(2);
    line(x,y+2,x-20,y+2);
    stroke(0);
    strokeWeight(2);
    point(x+15,y);
    strokeWeight(1.5);
    point(x+9,y-1);
    pop();

    //Play squeak when mouse reaches x=0;
    if(mousePos == 0)
    {
        mouseSound.play();
    }

    //Make mouse stop moving left after x=-15
    if(mousePos <= -15)
    {
        mousePos = -15
    }
    //Add dx to mouse position
    mousePos += mousedx;

}

function drawLightning()
{
    //Lightning artwork
    push();
    translate(random(25,-25),0);
    stroke(0,100,255);
    strokeWeight(3);
    line(90,142,107,160);
    line(107,160,90,190);
    line(90,190,105,220);
    line(105,220,95,250);
    line(95,250,107,280);
    line(90,317,107,280);
    stroke(255);
    strokeWeight(1);
    line(90,141,107,160);
    line(107,160,90,190);
    line(90,190,105,220);
    line(105,220,95,250);
    line(95,250,107,280);
    line(90,317,107,280);
    pop();
}

function drawPainting(x,y)
{   
    //Painting artwork
    push();
    noStroke();
    rectMode(CENTER);
    fill(120,60,0)
    rect(x,y,120,75);
    fill(220);
    rect(x,y,110,65);
    fill(0,170,190);
    circle(x,y,30)
    fill(180,0,150);
    circle(x+30,y+10,20)
    pop();
}

function drawBackdrop()
{
    push();
    noStroke();
    //Floor
    fill(120,70,10);
    rect(0,400,width,80);

    //Ceiling
    fill(120,60,0)
    rect(0,0,width,80);

    //Window
    rect(15,125,160,210);
    fill(170,100,0);
    rect(20,130,150,200);

    //Sky
    fill(52, 49, 69);
    rect(30,140,130,180)
    pop();
}

function windowLines(x,y)
{
    //Window frame stuff
    push();
    noStroke();
    fill(170,100,0);
    rectMode(CENTER);
    rect(x,y,150,7);
    fill(100,50,0);
    rect(x,y+3,130,2)
    pop();
}

function drawDrawer(x,y)
{
    push();
    noStroke();
    fill(170,100,0);
    rect(x,y,143,70);

    //Shadow
    fill(115,65,0)
    rect(x,y+70,143,70)

    //Back
    fill(190,120,0);
    rect(x+7,y+12,130,20);
    rect(x+7,y+40,130,20);

    //Drawers
    fill(220,150,0);
    circle(x+35,y+22,10);
    circle(x+105,y+22,10);
    circle(x+35,y+50,10);
    circle(x+105,y+50,10);
    pop();
}


function drawClock(x,y)
{
    push();
    noStroke();

    //Shadow
    fill(115,65,0);
    rect(x-25,y+150,52,100)

    //Light
    fill(220,150,0);
    circle(x+3,y+70,50);
    rect(x-22,y+70,50,100)
    circle(x+3,y+55,35)

    //Base
    fill(200,120,0);
    circle(x,y+70,50);
    rect(x-25,y+70,50,100)
    circle(x,y+55,35)


    //Shades
    fill(170,100,0);
    circle(x,y+55,25);
    circle(x,y+70,40);
    rect(x-15,y+100,30,65);
    ellipse(x,y+100,30,15);

    //Clock face
    fill(255);
    circle(x,y+70,34);
    fill(0);
    circle(x,y+70,2);

    //Clock Static Hand
    stroke(100);
    strokeWeight(1);
    line(x,y+70,x,y+60)
    
    //Clock Second Hand

    angle+= 6 //Add 6 degrees every frame (second)
    stroke(0);
    strokeWeight(0.5);
    let ax = x+cos(angle) * 14; //Polar x coordinates
    let ay = y+sin(angle) * 14; //Polar y coordinates
    line(x,y+70, ax, ay+70); //Draw clock hand

    //Detail
    stroke(235,180,0);
    strokeWeight(2);

    //Pendulum chime things
    line(x,y+94,x,y+120+abs(10*sin(angle)));
    line(x+4,y+94,x+4,y+100+abs(20*sin(angle)));

    pop();
}

A mouse tries to sneak past a sleeping cat, but the lightning keeps waking the cat up.

Looking Outwards 10: Computer music

Computer-generated music is not revolutionary, or well known in any way. Music is generally known as an artform, something people make to express themselves – something unique to human nature.

However, computer-generated music, more specifically procedural music, is widely utilized in today’s world; mostly to improve adaptive/dynamic soundtracks in video games. In many games released in the past 2 years, procedural music technology has been a staple for the Triple-A gaming industry. No one ever notices the procedural music because it does its work so seamlessly and subtly. Nowadays, every time a peaceful, ambient, background soundtrack switches to an intense, high-tempo, adrenaline-inducing beat in a game, you never really notice it. The software automatically generates extra notes, extra percussion beats, and even background vocals to make the transition between one soundtrack to another so smooth that almost no one notices.

The technology and intelligence required for a computer to interpolate one piece of music into another on-the-go, depending on the events taking place on-screen is actually quite impressive. Machine learning is used to train the AI by making it analyze many different soundtracks. This results in an AI that can compose a very limited amount of music, but just enough to make the transition between one soundtrack and another sound non-existent.

https://en.wikipedia.org/wiki/Adaptive_music

Project 09: Portrait

sketchDownload
//Nicholas Wong
//Section A
//nwong1@andrew.cmu.edu
//Assignment 09


var size = 10 //Default size of stroke

function preload()
{
	//A profile picture
	img = loadImage("https://i.imgur.com/1XXSpjL.png")
}

function setup()
{
	createCanvas(480,480);
	img.loadPixels(); //Load pixels

	//Set modes
	imageMode(CENTER);
	rectMode(CENTER);
	textAlign(CENTER);
	angleMode(RADIANS);

	//Set custom framerate
	frameRate(120)

}

function draw()
{
	//Offset canvas to fit my face in the middle
	translate(-100,10)

	//Get random x and y coordinates
	let x = floor(random(width));
	let y = floor(random(height));

	//Get color of coordinates
	let pix = img.get(x,y);

	//Create strokes
	drawStrokes(x,y,pix);

	drawInstructions();
}

function drawStrokes(x,y,pix)
{
	push();
	translate(100,0) //Recenter canvas
	translate(x,y);
	rotate(revolveMouse(x,y));//Rotate strokes around mouse

	//Draw stroke
	stroke(pix, 128);
	strokeWeight(0.25*size + random(0,2)); //Stroke size influenced by mouse scroll
	line(0,-size + random(0,2),0,size+ random(0,2)); //Stroke length based on mouse scroll
	pop();
}

function revolveMouse(x,y)
{
	//Generates angle from mouse position and (x,y) coordinate
	let dx = mouseX - x;
	let dy = mouseY - y;
	let angle = atan2(dy,dx)
	return angle; //Returns angle
}

function mouseWheel(event)
{
	//Check if scrolling up
	if (event.deltaY < 0)
	{
		size++; //Increase size
	}
	else //Scrolling down
	{
		size -= 1; //Decrease size
	}
}

function drawInstructions()
{
	//Text box at bottom of canvas
	push();
	translate(100,10);
	noStroke();
	fill(0)
	rect(width/2,height-50,285,35)
	fill(255)
	textSize(10)
	text('SCROLL MOUSEWHEEL TO CHANGE STROKE SIZE',width/2,height-47)
	pop();
}

Strokes radiate and rotate around mouse pointer, mouse scrolling changes the stroke size; scroll up to increase size, scroll down to decrease size. Here are some examples with varying mouse positions, stroke sizes, and durations.

Looking Outwards 09: Eggdog

This looking outward is to honor and spread awareness of Eggdog, a CG character based off of a real Pomeranian that was groomed to look like an egg. Personally I find this 3D-model-turned-meme a very interesting, intriguing, and very relevant to Week 5’s Looking Outwards topic of 3D Computer Graphics. Eggdog’s prevalence on social media shows how 3D modeling, rendering, and animation has become so accessible over just the past decade. Almost anyone can download free 3D modeling software like Blender and learn how to create something as simple, elegant, and beautiful as Eggdog. This point was also made by the student who wrote about Eggdog.

Eggdog represents both today’s widespread availability and accessibility to 3D modeling software, and today’s ease of transferring information through social media. Any individual in the world can create anything, from Eggdogs, to feature films, to hit video games, all by themselves, and share it with the rest of the world. Eggdog, at its very core, represents the creative power of technology in the hands of everyday citizens.

eggdog : iamveryrandom

Looking Outwards: 08

Mike Tucker and his company, Magic Leap, are working on a unique variation of augmented reality: Spatial computing. Magic Leap One is a head-mounted virtual retinal display that superimposes digital imagery over real world objects through projecting digital “light fields” into the user’s eye. The device is stand-alone, and does not require an external computer / processing unit. The software can actively scan and create a digital representation of the surrounding environment to accurately superimpose 3D geometry over objects. Mike’s work often involves elevating spatial experiences, and creating new forms of interacting with spaces, something that I also explore as an architecture student.

Mike Tucker’s Eyeo festival presentation mainly focused on his installation work in San Francisco; The Microsoft Infinity Room. The room visualizes the data of a simple quarter, and how such a small, seemingly insignificant amount of currency can create effects that cascade into large changes that can affect the global economy. The experience is a 360-degree virtual tour that visualizes concepts and topics that aren’t easy to grasp.

Mike’s work does the talking for him. His presentations are clear and concise, condensing complex topics into digestible, relatable sentences. The accompanying behind-the-scenes visuals and images further convey the concepts he discusses.

Project 07: Butterfly Curve

sketchDownload

var n = 100; //Number of points
var r = 50; //Radius

var x = [] //List of X values
var y = [] //List of Y values
var t = [] //Parameter 


function setup() 
{
	createCanvas(480, 480);
	frameRate(60)
	//Initialize Butterfly curve by assigning X, Y and T values
    for (let i = 0; i < n; i++) {
        t[i] = random(0, 180);
        //Equations taken from https://mathworld.wolfram.com/ButterflyCurve.html
        x[i] = r * sin(t[i]) * (exp(cos(t[i])) - 3 * cos(4 * t[i]) - pow(sin(t[i] / 10), 5));
        y[i] = r * cos(t[i]) * (exp(cos(t[i])) - 3 * cos(4 * t[i]) - pow(sin(t[i] / 10), 5));
    }
}


function draw() 
{

    background(0);
    //Make (0,0) center of canvas
    translate(width / 2, height / 2);


    let my = map(mouseY,0,height,18*PI,6*PI); //Map mouse Y to number of rotation iterations of butterflies
    push();
   	noFill();
    stroke(100)
    strokeWeight(0.25)

    //Begin curve for butterfly
    beginShape();
    for (let i = 0; i < my; i += 0.01)
    {
    	//Equations taken from https://mathworld.wolfram.com/ButterflyCurve.html
      	let bx = r * sin(i) * (exp(cos(i)) - 3 * cos(4 * i) - pow(sin(i / 10), 5));
      	let by = r * cos(i) * (exp(cos(i)) - 3 * cos(4 * i) - pow(sin(i / 10), 5));
      	//Vertex has X and Y points corresponding to parametric equations
      	vertex(bx,by)
    }
    endShape();
    pop();

    //Draw flying circles
    push();
    fill(255);
    noStroke();
    //Loop for number of circles
    for (let i = 0; i < n; i++) 
    {
    	let mx = map(mouseX,0,width,-0.005,0.005); //Map mouse X to speed at which parameter changes (from negative to positive speeds)
        t[i] += mx; //Add mapped mouse X to parameter

        //Reset parameter if it exceeds 180 degrees
        if (t[i] > 180)
        {
        	t[i] = 0;
        }

        //Equations taken from https://mathworld.wolfram.com/ButterflyCurve.html
        x[i] = r * sin(t[i]) * (exp(cos(t[i])) - 3 * cos(4 * t[i]) - pow(sin(t[i] / 10), 5));
        y[i] = r * cos(t[i]) * (exp(cos(t[i])) - 3 * cos(4 * t[i]) - pow(sin(t[i] / 10), 5));

        //Draw circle
        circle(x[i], y[i], 3);
    }
    pop();
}

The Butterfly curve seemed really similar to the Lorentz attractor curves I was looking for last week’s Looking Outwards. I initially wanted to make a circle follow the trail of the curve and have the mouseX determine the speed, however I realized that it was actually easier to have multiple circles follow the path.

MouseX controls speed and direction of circles, MouseY controls amount of curve iterations of the butterfly curve.

Looking Outwards 7:

Nathalie Miebach combines her love of art, science, and data analysis to create interesting sculptures that reflect the primal forces of nature. She transforms data taken from massive storms and turns them into 3-dimensional sculptures. Meteorological data is taken and then transformed into sound, which is then arranged into a “musical score” built entirely of weather data. This score is then combined with the sounds of human experiences and interpretations of the weather, creating a juxtaposition of objective and subjective data. This musical composition is then turned into a sculpture that reflects both the empirical data, and nuanced human emotions of a storm.

I really appreciate the subjective, sensational effect the sculptures have. Some of them look like actual buildings being torn apart by the wind, and some look like the distortions and disturbances in the air as a storm rips through.

Nathalie Miebach's Sculptural Soundtracks for Storms – Brain Pickings
The chaos of a storm ripping through a city
Colorful Basket Weaving Sculptures by Nathalie Miebach Transform Weather  Data into Visual Art | Colossal
The volume and density of a hurricane