/*
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.
]]> /*
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:
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
//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.
]]>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.
]]>//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.
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.
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.
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.
]]>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.