// Alec Albright
// aalbrigh
// Section B
// Project 12 - Final Project
var video;
var nPoints = 100; // number of points used to draw curves
var previous; // previous image from camera
var threshold = 150; // used to determine if a pixel is different enough to consider it "moving"
var motionX = 0; // main coordinate of X motion
var motionY = 0; // main coordinate of Y motion
var lerpX = 0; // X coordinate for smoothing of motion
var lerpY = 0; // Y coordinate for smoothing of motion
var higherLove; // Whitney Houston's "Higher Love"
var low; // Flo Rida's "Low"
var irreplaceable; // Beyonce's "Irreplaceable"
var newBooty; // Bubba Sparxxx's "Ms. New Booty"
var higherVol; // Higher love volume
var lowVol; // low volume
var irrepVol; // irreplaceable volume
var bootyVol; // new booty volume
function preload(){
higherLove = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Higher-Love.wav");
low = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Low.wav");
irreplaceable = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Irreplaceable.wav");
newBooty = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/New-Booty.wav");
}
function soundSetup() { // setup for audio generation
// making sine
sine = new p5.Oscillator();
sine.setType("sine");
//sine.start();
// making sawtooth
sawtooth = new p5.Oscillator();
sawtooth.setType("sawtooth");
//sawtooth.start();
// making square wave
square = new p5.Oscillator();
square.setType("square");
square.freq(440);
//square.start();
}
function setup(){
createCanvas(480, 480);
angleMode(RADIANS);
video = createCapture(VIDEO);
video.size(480, 480); // attempt to size the camera.
video.hide(); // this hides an unnecessary extra view.
// prepping to copy previous frame for difference in motion
previous = createImage(480, 480, RGB);
useSound();
higherLove.play();
higherLove.setVolume(0);
higherLove.loop();
low.play();
low.setVolume(0);
low.loop();
irreplaceable.play();
irreplaceable.setVolume(0);
irreplaceable.loop();
newBooty.play();
newBooty.setVolume(0);
newBooty.loop();
}
function draw(){
var count = 0; // number of pixel instances we've looped through
var sumX = 0; // sum of motion X coordinates
var sumY = 0; // sum of motion X coordinates
// making camera actually mirror user
push();
translate(width, 0);
scale(-1, 1);
image(previous, 0, 0);
pop();
loadPixels();
video.loadPixels(); // this must be done on each frame.
previous.loadPixels();
// comparing all pixels to previous image
for (var x = 0; x < video.width; x ++) {
for (var y = 0; y < video.height; y ++) {
var location = (x + y * video.width) * 4;
// finding previous and current colors
// previous
var red1 = previous.pixels[location];
var green1 = previous.pixels[location + 1];
var blue1 = previous.pixels[location + 2];
// current
var red2 = video.pixels[location];
var green2 = video.pixels[location + 1];
var blue2 = video.pixels[location + 2];
var diff = distSquared(red1, green1, blue1, red2, green2, blue2);
// checking whether they are different enough to call motion
if (diff > threshold * threshold) {
sumX += x;
sumY += y;
count ++;
}
}
}
updatePixels();
// only count it as a different frame if more than 30 pixels have changed
// find main X and Y coordinate of motion, this will be our control for everything
if (count > 100) {
motionX = sumX / count;
motionY = sumY / count;
}
// maintaining mirrored scale for user interface
push();
translate(width, 0);
scale(-1, 1);
// smoothing out how the point of focus is travelling
lerpX = lerp(lerpX, motionX, 0.1);
lerpY = lerp(lerpY, motionY, 0.1);
// drawing point so user knows where the main motion point is
stroke("black");
fill("white");
ellipse(lerpX, lerpY, 20, 20);
pop();
push();
translate(width / 2, height / 2);
// draw all the shapes
drawHippopede();
drawEpicycloid();
drawHypotrochoid();
pop();
previous.copy(video, 0, 0, video.width, video.height, 0, 0, video.width, video.height);
// creating slight boundaries for better sound isolation
if(lerpY < 200 || lerpY > 320) {
// letting contrast between top and bottom come through
bootyVol = 0;
irrepVol = 0;
newBooty.setVolume(bootyVol);
irreplaceable.setVolume(irrepVol);
// as we move up, more higher love/less low
// volume 0 to 1
higherVol = map(lerpY, 0, width, 0, 1);
higherLove.setVolume(1 - higherVol);
lowVol = map(lerpY, 0, width, 0, 1);
low.setVolume(lowVol);
} else {
// letting contrast between right and left come through
higherVol = 0;
lowVol = 0;
higherLove.setVolume(higherVol);
low.setVolume(lowVol);
// as we move right, more new booty/less irreplaceable
// volume 0 to 1
bootyVol = map(lerpX, 0, width, 0, 1);
newBooty.setVolume(1 - bootyVol);
irrepVol = map(lerpX, 0, width, 0, 1);
irreplaceable.setVolume(irrepVol);
}
}
// draws Hippopede
function drawHippopede() {
var x; // x coordinate of vertex
var y; // y coordinate of vertex
var r; // polar coordinate
var a = lerpX / 3 // main parameter of the curve
var b = map(a, 0, 480, 100, 200); // circle radius
var rotation = map(lerpY, 0, 480, 0, TWO_PI); // amount of rotation
// thickness of line proportional to the circle radius
strokeWeight(b / 6);
stroke(255, 255, 255, 150);
noFill();
// rotate shape
push();
rotate(rotation);
// start drawing the shape, one point at a time
beginShape();
for(var i = 0; i < nPoints; i++){
var t = map(i, 0, nPoints, 0, TWO_PI);
// find r (polar equation)
r = sqrt(4 * b * (a - b * sinSq(t)));
// convert to x and y coordinates
x = r * cos(t);
y = r * sin(t);
// draw a point at x, y
vertex(x, y);
}
endShape();
pop();
}
// draws hypotrochoid
function drawHypotrochoid() {
var x; // x coordinate of vertex
var y; // y coordinate of vertex
var a = map(lerpX, 0, 480, 20, 100); // radius of the interior circle
var b = 3; // radius of the petals
var h = lerpX / 10; // distance from center of interior circle
var red = map((lerpX + lerpY) / 2, 0, 480, 0, 255); // how much red
var blue = map(lerpY, 0, 480, 0, 255); // how much blue
var alpha = map(lerpX, 0, 480, 50, 150); // how opaque
var rotation = map(lerpY, 100, 300, 0, TWO_PI); // amount of rotation
strokeWeight(2)
stroke(255, 255, 255, 150);
// control color and opacity with mouse location
fill(red, 0, blue, alpha);
// control rotation with lerpY
push();
rotate(rotation);
// create the shape itself
beginShape();
for(var i = 0; i < nPoints; i++) {
var t = map(i, 0, nPoints, 0, TWO_PI);
// use parametric euqations for hypotrochoid to find x and y
x = (a - b) * cos(t) + h * cos((a - b) / b * t);
y = (a - b) * sin(t) - h * sin((a - b) / b * t);
// draw a point at x, y
vertex(x, y)
}
endShape(CLOSE);
pop();
}
// draws an epicycloid
function drawEpicycloid() {
var x; // x coordinate of vertex
var y; // y coordinate of vertex
var a = map(lerpX, 0, 480, 20, 100); // radius of interior circle
var b = map(lerpY, 0, 480, 5, 30); // radius of petals
var blue = map((lerpX + lerpY) / 2, 0, 480, 0, 255); // how much blue
var red = map(lerpY, 0, 480, 0, 255); // how much red
var rotation = map(lerpY, 100, 300, 0, TWO_PI); // how muhc rotation
// control color with mouse location
strokeWeight(10)
stroke(red, 0, blue, 150);
// control rotation with mouse location
push();
rotate(rotation);
// start drawing shape
beginShape();
for(var i = 0; i < nPoints; i++) {
var t = map(i, 0, nPoints, 0, TWO_PI);
// find coordinates using epicycloid parametric equations
x = (a + b) * cos(t) - b * cos((a + b) / b * t);
y = (a + b) * sin(t) - b * sin((a + b) / b * t);
// draw a point at x, y
vertex(x, y);
}
endShape();
pop();
}
// defines sin^2 using trigonometric identities
function sinSq(x) {
return((1 - cos(2 * x)) / 2);
}
function distSquared(x1, y1, x2, y2) {
let dx = x2 - x1;
let dy = y2 - y1;
return (dx * dx) + (dy * dy);
}
For the Final Project, I wanted to do something that had to deal with music, as it is my primary focus at CMU, but I also wanted to try doing something computationally complex that I would certainly be challenged by. Thus, the idea to create a motion detection music player was born! I also wanted to keep it fun, so I decided to play music related to each quadrant: “Irreplaceable” – Beyonce for the left (to the left, to the left…), “Higher Love” – Whitney Houston for the top, “Low” – Flo Rida for the bottom, and “Ms. New Booty” – Bubba Sparxxx for the right (get it right, get it right get it tight). For better user interfacing, I also included a floating point that denotes where the program has tracked the average motion.
The process was most difficult in rendering and comparing one frame to its previous frame in order to create a successful motion detection program. It was interesting mapping the visualization to the motion detection as well, giving each song its own visual identity.
In order to run the program, you must allow the website to access your video camera. However, I have included a demo video below for those who would rather see that.
//Minjae Jeong
//Section B
//minjaej@andrew.cmu.edu
//Final Project
var human = []; //array to save x y position
var count = 0;
var transp = 255; //transparency
function preload() {
//simplified world map
worldMap = loadImage("https://i.imgur.com/Kviuun0.png");
}
function setup() {
createCanvas(600, 348);
textAlign(CENTER);
}
function draw() {
background(132, 181, 229); //rgb of image's body of water
tint(255, transp); //this makes the water to fill up as you click
image(worldMap, 0, 30);
//title
textSize(24);
fill('red');
text("UNTIL WHEN CAN THE EARTH SUPPORT US?", width / 2, 27);//Have you thought about it
//Draw human + CO2
strokeWeight(1);
for (var i = 0; i < human.length; i++) {
xx = human[i][0];
yy = human[i][1];
fill('black');
drawHuman(xx, yy);
drawco2(xx, yy - 5);
}
//display global warming text
if (count > 20 & count < 40) {
textSize(20);
fill("red");
text("GLOBAL WARMING", 350, 330);
// count = count + 1;
}
//display "No more penguins and polar bears." Could be very soon
if (count > 40 & count < 60) {
textSize(20);
fill("red");
text("NO MORE PENGUINS & POLAR BEARS", 320, 50);
}
//display "No more place to live"
//(Elon Musk please)
if (count > 70 & count < 100) {
textSize(27);
fill("red");
text("NO MORE PLACE TO LIVE", width / 2, height / 2);
}
//changes background color to black
if (count > 90 & count < 100) {
fill("black");
rect(0, 0, width, height);
fill("red");
text("NO MORE PLACE TO LIVE", width / 2, height / 2);
}
//"What will you do?"
if (count >= 100){
fill('black');
rect(0, 0, width, height);
fill('red');
textSize(30);
text("WHAT WILL YOU DO?", width / 2, height /2);
}
}
//draw human
function drawHuman(x, y) {
ellipse(x, y, 5);
rect(x - 2, y + 5, 4, 11);
line(x - 2, y + 7, x - 8, y + 2);
line(x + 2, y + 7, x + 8 , y + 2);
}
//CO2
function drawco2(x, y) {
textSize(9);
text("+ CO2", x, y);
}
function mousePressed() {
human.push([mouseX, mouseY]); //Save mouseX, mouseY
transp = transp - 3.3; //Water fills up the land
count += 1;
}
For the final project, I made an interactive map that I wish to deliver some message. Click to add people on the map, keep on adding as it represents human population on the Earth.
My final project is little different from the proposal, because the original idea, which was to indicate temperature rise and deforestation, did not have clear message compared to what it actually shows. So I rather made a simple interactive map that shows what is happening as we grow on the Earth.
]]>//Julia Nishizaki
//Section B
//jnishiza@andrew.cmu.edu
//Final Project - ABCs of Climate Change
//variables for climate change effects, uses true/false statements to make effects appear/disappear
var cE = {
lakeColor: false, //algae blooms
flowers: false, //biodiversity
clouds: false, //carbon footprint
trees: true, //deforestation
gas: false, //greenhouse gases
mtn: false, //hazardous waste
hill: false, //invasive species
jeopardy: false, //jeopardy
house: false, //population growth
sky: false, //smog
field: false, //toxic pollutants
building: false, //urban sprawl
lake: false, //water levels
deadz: false, //zones that are dead
}
//variables to help with effects of climate change
var lakeWidth = 200; //initial width of lake
var lakeHeight = 35; //height of lake
var skyHeight = 0; //height of sky for smog
var cloudX = 475; //starting x position for cloud
var gasX = 475; //starting x position for gas cloud
var jtranslu = 0; //starting opacity for "smoke screen", jeopardy
//variables for the window and its dimensions
var win = {
ws: 125, //distance from window to right and left sides of canvas
wt: 40, //distance from window to top of canvas
wb: 160, //distance from window to bottom of canvas
frm: 5, //width of window frame
dis: 5, //displacement outside of canvas
}
//variables for colors used throughout, especially for objects that change color
var colors = {
hill: 80, //light green hill (HSB)
mtnb: 70, //purple mountains (HSB)
sky: '#8ED9EF', //light blue of sky
smogop: 80, //opacity of smog in background
field: 'green', //green
lakeh: 55, //hue value of lake (HSB)
lakes: 50, //saturation value of lake (HSB)
lakeb: 100, //brightness value of lake (HSB)
fieldb: 60, //brightness value of field (HSB)
wall: 230, //light gray of walls
table: 150, //dark gray of table
flower: 'purple', //purple flowers
plnflw: 'green', //green flowers
type: '#8BC63F', //light green of type
}
//arrays that store letters and each letter's climate change info
var alphabetLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
var letterInfo = [ //stores copy on climate change ABCs
"Algae Blooms: toxic algae can poison water and create dead zones",
"Biodiversity: the variety of life on the planet",
"Carbon Footprint: the amount of carbon dioxide each of us produces",
"Deforestation: the reduction of trees due to natural forces or human activity",
"Extinctions: the death of all individuals of a species",
"Fossil Fuels: nonrenewable fuels that are burned for energy like coal and gas",
"Greenhouse Gases: gases like methane, trap heat and warm the atmosphere",
"Hazardous Waste: waste that pose a risk to human health and the environment",
"Invasive Species: any organism not native to an ecosystem that causes harm",
"Jeopardy: danger of loss, harm, or failure",
"Keystone Species: a species that is critical to the survival of other species",
"Landfill: a site where wastes are dumped for permanent disposal",
"Microplastics: very small pieces of plastic that pollute the environment",
"Nonrenewable: resources that can't be replenished onced used",
"Ozone Layer: a thin protective layer of gas above Earth that filters UV radiation",
"Population Growth: an increase in the total human population",
"Quotas Insufficient: limits and restrictions in environmental policies not met",
"Runoff: stormwater from cities or farms that carry pollutants into water systems",
"Smog: dust, smoke, or chemical fumes that pollute the air",
"Toxic Pollutants: contaminate areas and cause death, disease, or birth defects",
"Urban Sprawl: expansion of auto-dependent developments over large areas of land",
"Vulnerability: susceptibility to harm from exposure to stresses",
"Water Level Rise: rising sea levels due to global warming and melting glaciers",
"Xenobiotic: non-natural or man-made substances found in the environment",
"Yield: amount of crops produced per unit area",
"Zones that are Dead: dead zones are caused by hypoxia, or lack of oxygen in water",
];
function setup() {
createCanvas(600, 480);
frameRate(30);
}
function draw() {
background(colors.sky); //sets the background as a light blue
prepEnvironEffects(); //connects each key to a variable
drawLandscape(); //creates all elements of the landscape
drawRoom(); //creates all elements of the room
typedLetterAlphabet(); //displays the alphabet
typedLetterInfo(); //displays the words and definitions
}
function prepEnvironEffects() {//when a particular key is pressed, the variable associated with that key switches from false to true
if (key == 'a') { //algae blooms
cE.lakeColor = true;
}
if (key == 'b') { //biodiversity
cE.flowers = true;
}
if (key == 'c') { //carbon footprint
cE.clouds = true;
}
if (key == 'd') { //deforestation
cE.trees = false;
}
if (key == 'g') { //greenhouse gases
cE.gas = true;
}
if (key == 'h') { //hazardous waste
cE.mtn = true;
}
if (key == 'i') { //invasive species
cE.hill = true;
}
if (key == 'j') { //jeopardy
cE.jeopardy = true;
}
if (key == 'p') { //population growth
cE.house = true;
}
if (key == 's') { //smog
cE.sky = true;
}
if (key == 't') { //toxic pollutants
cE.field = true;
}
if (key == 'u') { //urban sprawl
cE.building = true;
}
if (key == 'w') { //water level rise
cE.lake = true;
}
if (key == 'z') { //zones that are dead
cE.deadz = true;
}
}
//Creates elements in the landscape, and calls for changes to those elements
function drawLandscape() {
makeClouds(); //creates clouds for carbon footprint and greenhouse gas, letters c and g
changeSky(); //creates smog screen in background, letter s
changeMtnHill(); //changes color of mountains and hills, letters h and i
var landscapeScale1 = 0.004; //detail in hills
var landscapeScale2 = 0.018; //detail in mountains
//creates mountains in the background
colorMode(HSB, 100);
stroke(70, 30, colors.mtnb);
strokeWeight(1);
for (var x = 0; x < width; x ++) {
var l = (x * landscapeScale2);
var y = map(noise(l), 0, 1, height * 0.2, height * 0.5); //constrains hills
line(x, y, x, height); //creates vertical lines, forming a solid shape
}
colorMode(RGB);
makeBuilding(); //creates buildings when letter u is pressed
//creates hills in the middleground
colorMode(HSB, 100); //switches color mode to HSB to help with color changes
stroke(25, 50, colors.hill);
for (var x = 0; x < width; x ++) {
var l = (x * landscapeScale1);
var y = map(noise(l), 0, 1, height * 0.4, height * 0.6); //constrains hills
line(x, y, x, height); //creates vertical lines, forming a solid shape
}
//creates field in foreground
noStroke();
fill(28, 100, colors.fieldb); //field color
rect(0, height * 0.55, width, height * 0.35);
changeField(); //changes color of field, letter t
//creates lake
fill(colors.lakeh, colors.lakes, colors.lakeb);
ellipse(175, 286, lakeWidth, lakeHeight);
changeLake(); //changes color and size of lake, letters a, w, and z
colorMode(RGB); //switches color mode back to RGB
makeFlowers(); //makes flowers, alternating colors, becomes one color with letter b
makeHouse(); //makes houses, letter p
makeTrees(); //makes single yellow tree in foreground, tree disappears with letter d
smokeScreen(); //creates a semi-transparent grey layer with letter j
}
//makes and moves the clouds
function makeClouds() {
if (cE.clouds == true) { //makes a cloud for carbon footprint, letter c
drawClouds(cloudX, 120, 150, 50, 150);
cloudX = cloudX - 2;
if (cloudX < win.ws - 150) {
cloudX = 475;
}
}
if (cE.gas == true) { //makes a cloud for greenhouse gases, letter g
drawClouds(gasX, 180, 220, 75, 100);
gasX = gasX - 1;
if (gasX < win.ws - 220) {
gasX = 475;
}
}
}
//draws the clouds
function drawClouds(locationX, locationY, width, height, color) {
push();
fill(color);
translate(locationX, locationY);
rect(0, - height, width, height, 50, 50, 50, 50);
pop();
}
//adds "smog" in background
function changeSky() {
if (cE.sky == true) {
fill(80, colors.smogop);
noStroke();
rect(0, height * 0.55 - skyHeight, width, skyHeight);
skyHeight = constrain(skyHeight, 0, 300) + 3;
}
}
//changes colors of mountains and hills
function changeMtnHill() {
if (cE.mtn == true) { //changes mountain colors
colors.mtnb = constrain(colors.mtnb, 20, 70) - 5;
}
if (cE.hill == true) { //changes hill colors
colors.hill = constrain(colors.hill, 30, 80) - 5;
}
}
//makes the buildings for urban sprawl
function makeBuilding() {
if (cE.building == true) { //from left to right
drawBuildings(125, 37, 130, 180);
drawBuildings(162, 62, 110, 150);
drawBuildings(224, 50, 120, 200);
drawBuildings(274, 37, 100, 130);
}
}
//draws buildings
function drawBuildings(locationX, buildW, buildH, color) {
push();
noStroke();
fill(color);
translate(locationX, height * 0.58);
rect(0, - buildH, buildW, buildH);
//windows in buildings
fill(255);
for (var x = 0; x < (buildW / 6) - 1; x ++) {
for (var y = 0; y < 200; y ++) {
rect(2 + x * 6, - buildH + 4 + y * 8, 3, 4);
}
}
pop();
}
//changes lake size and color
function changeLake() {
if (cE.lake == true) { //makes larger for water level
lakeWidth = constrain(lakeWidth, 200, 350) + 5;
}
if (cE.lakeColor == true) { // becomes green for algae
colors.lakeh = constrain(colors.lakeh, 30, 55) - 0.75;
}
if (cE.deadz == true) { //becomes dark for dead zones
colors.lakes = constrain(colors.lakes, 50, 100) + 5;
colors.lakeb = constrain(colors.lakeb, 35, 100) - 5;
}
}
//changes color of field
function changeField() {
if (cE.field == true) {
colors.fieldb = constrain(colors.fieldb, 20, 60) - 2;
}
}
//makes row of flowers at base of hills
function makeFlowers() {
for (var i = 0; i < 20; i ++) {
strokeWeight(2);
for (var g = 0; g < 6; g ++) {
if (i % 2) { //alternates colors of flowers to represent biodiversity
stroke(colors.plnflw);
push();
translate(win.ws + i * 25, height * 0.55);
rotate(g * 60);
line(0, 0, 0, 3);
pop();
} else {
stroke(colors.flower);
push();
translate(win.ws + i * 25, height * 0.55);
rotate(g * 60);
line(0, 0, 0, 3);
pop();
}
}
}
if (cE.flowers == true) { //changes color of flowers to single color, removal of biodiversity
colors.flower = colors.plnflw;
}
}
//makes houses for population growth
function makeHouse() {
if (cE.house == true) {
drawHouses(320, height * 0.58, '#FCAD77', '#E8762A', 0.9); //left
drawHouses(375, height * 0.57,'#7BE0FF', '#1CB8E8', 0.8); //right
drawHouses(350, height * 0.59,'#B09DCC', '#9274C1', 1.0); //middle
}
}
//draws houses
function drawHouses(locationX, locationY, colorHouse, colorDoor, houseScale) {
push();
noStroke();
fill(colorHouse);
translate(locationX, locationY);
scale(houseScale);
rect(0, -20, 40, 20);
fill('white');
triangle(-5, -20, 45, -20, 20, -30);
rect(24, -15, 10, 10);
fill(colorDoor);
rect(8, -15, 8, 15);
pop();
}
//makes tree in foreground of landscape
function makeTrees() {
if (cE.trees == true) { //the tree disapears when key is pressed, as key switches variable to false
push();
rectMode(CENTER);
translate(440, 110);
noStroke();
fill(249, 176, 30); //yellow of tree
rect(0, 0, 130, 200, 40, 40, 40, 40);
//tree branches
strokeWeight(15);
stroke(124, 20, 22);
line(0, -50, 0, 225);
strokeWeight(10); //thinner branches
line(0, 80, 40, 40);
line(0, 20, -40, -20);
pop();
}
}
function smokeScreen() { //creates grey screen
if (cE.jeopardy == true) {
noStroke();
jtranslu = constrain(jtranslu, 0, 80) + 15;
fill(150, jtranslu);
rect(win.ws, win.wt, 350, 300)
}
}
//creates all aspects of the room - window, window frame, walls, table, poster, instructions
function drawRoom() {
rectMode(CORNER);
noStroke();
//walls of the room
fill(colors.wall);
rect(-win.dis, -win.dis, win.ws + win.dis, height + win.dis * 2);
rect(width - win.ws, -win.dis, win.ws + win.dis, height + win.dis * 2);
rect(0, height - win.wb, width, win.wb);
rect(0, 0, width, win.wt);
//gray "table" below window where alphabet and definitions appear
fill(colors.table); //medium gray
rect(0, height - 130, width, 130);
//white lines that divide window
stroke(255);
strokeWeight(4);
line(width / 2, win.wt - win.frm, width / 2, height - win.wb + win.frm);
line(win.ws - win.frm, (height - win.wb) / 2 + win.wt / 2, width - win.ws + win.frm, (height - win.wb) / 2 + win.wt / 2);
//white border around the window
strokeWeight(10);
line(win.ws - win.frm, win.wt - win.frm, win.ws - win.frm, height - win.wb + win.frm);
line(width - win.ws + win.frm, win.wt - win.frm, width - win.ws + win.frm, height - win.wb + win.frm);
line(win.ws - win.frm, win.wt - win.frm, width - win.ws + win.frm, win.wt - win.frm);
line(win.ws - win.frm, height - win.wb + win.frm, width - win.ws + win.frm, height - win.wb + win.frm);
drawPoster(); //draws the poster to the left of window
drawInstructions(); //draws instructions on the gray "table"
}
function drawPoster() { //creates poster telling you to refresh
push();
noStroke();
rectMode(CENTER);
angleMode(DEGREES);
textAlign(CENTER);
fill(255);
translate(60, 165);
rotate(-3); //rotates poster slightly
rect(0, 0, 75, 100);
//pin at the top of the poster
fill(colors.table);
ellipse(0, -40, 5, 5);
//writing in gray telling you to refresh
textSize(12);
textLeading(15); //sets leading
var poster = "Refresh\npage\nto\nrestart"; //puts each word on a new line
text(poster, 0, -17);
pop();
}
function drawInstructions() { //creates instructions
textAlign(CENTER);
noStroke();
fill(255);
var textLocation = 375;
textSize(12);
text("Press and hold down keys to see some ABCs of climate change", width / 2, textLocation);
}
//creates alphabet
function typedLetterAlphabet() {
for (var i = 0; i < 26; i ++) {
textAlign(CENTER);
textSize(20);
noStroke();
var alphabetLocation = 400;
var x = map(i, 0, alphabetLetters.length, 50, width - 30);
if (keyCode === 65 + i) { //when key is down, letter turns grey
fill(100);
text(alphabetLetters[i], x, alphabetLocation);
} else { //all letters green when not pressed
fill(colors.type);
text(alphabetLetters[i], x, alphabetLocation);
}
}
}
//creates climate change info
function typedLetterInfo() {
textAlign(CENTER);
textSize(15);
fill(255);
for (var i = 0; i < 26; i ++) {
if (keyCode === 65 + i) {
text(letterInfo[i], width / 2, height - 45);
}
}
}
//when key released, already pressed letters disapear
function keyReleased() { //replaces already clicked letters and their info with spaces in the respective arrays
for (var i = 0; i < 26; i ++) {
if (keyCode == 65 + i) {
alphabetLetters.splice(i, 1, " ");
letterInfo.splice(i, 1, " ");
}
}
}
For this project, I initially wanted to use sound and the typing keyboard in order to create an instrument out of sounds related to the environmental crisis. However, I decided to instead pivot towards creating an interactive and visual display of some “ABCs” of climate change. When you type and hold down a key, a word that starts with that letter will appear, along with that word’s definition. For a little less than half of the letters in the alphabet, something related to the word will happen on the landscape that is visible outside of the window. I wanted to keep the interactions fairly simple, while still conveying some of the effects of climate change, global warming, and our actions as a society.
]]>For my final project, I really wanted to work with text and explore alternate ways of moving through a poem. I chose to focus on one of my favorite poets, pablo neruda, and chose his poem, Ode to Things, as it has a lot of beauty to it.
// ilona altman
// final project
// section a
// iea @ andrew.cmu.edu
// this is a poem showcase of
var odetothings;
let fromHere;
let toHere;
let thefont; //allegra sans from GoogleFont
let poemletters = []; //array of letters
let poem = "ode to things by neruda - "; // title of the poem
let reversedpoem = reverseString(poem); // reversed
let nextimageCount; //image counter
let imagelinks= ['https://i.imgur.com/EiIMWxn.png',
'https://i.imgur.com/XCmsYws.png',
'https://i.imgur.com/fQZf2Sc.png'];
let imagesofthings = []; // image array
let currentThingImage;
function preload() {
//loading the text and the poem
odetothings = loadStrings("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/ode-2.txt");
//thefont = loadFont('thefont.ttf'); (cannot figure out hot to upload font for WordPress)
//loading the images
for (l = 0; l < imagelinks.length; l++) {
imagesofthings[l] = loadImage(imagelinks[l]);
}
}
function setup() {
createCanvas(450,640);
//initializing variables
fromHere = 0;
toHere = 14;
nextimageCount = 0;
nextimage = 0;
//initial placement for letters in a circle
for (let i = 0; i < poem.length; i ++) {
var radius = 120;
var angle = i * TWO_PI/poem.length;
var inputX = radius * sin(angle);
var inputY = radius * cos(angle);
var inputL = reversedpoem.charAt([i]);
poemletters[i] = makeLetters(inputL, inputX, inputY);
}
}
function draw() {
background(255,255,255);
//images rotating
push();
imageMode(CENTER);
rotate(frameCount/10000);
currentThingImage = image(imagesofthings[nextimage],width/2,height/3);
pop();
//updating the position of the letters
Update();
// making sure that there is continuous text
if (toHere > odetothings.length){
fromHere = 0;
toHere = 14;
}
// the text on the bottom that runs through the poem
for (var i = fromHere; i < toHere; i++) {
textSize(14);
//textFont(thefont);
fill(150,190,150);
var placeY = 340 + (i%14) * 20
text(odetothings[i], width/4, placeY);
}
}
// reversing the string so the text is easier to read
function reverseString(str) {
var splitting = str.split("");
var reversing = splitting.reverse();
var joined = reversing.join("");
return joined;
}
// the object of each letter
function makeLetters(inputL, inputX, inputY) {
var ltr = {letter: inputL,
px: inputX,
py: inputY,
showing: showLetters}; // draw the letter
return ltr;
}
function showLetters() {
push();
translate(width/2, height/3.5);
rotate(frameCount/1000);
//textFont(thefont);
textSize(30);
textAlign(CENTER);
fill(180,100,130);
text(''+ this.letter, this.px, this.py);
pop();
}
function Update() {
for (var i = 0; i < poemletters.length; i++){
poemletters[i].showing();
}
}
// when the mouse is pressed, the text cycles through
function mouseClicked() {
fromHere = fromHere + 14;
toHere = toHere + 14;
nextimageCount = nextimageCount + 1;
nextimage = nextimageCount%3;
}
]]>For this final project, I created a “Catch & and Run” game. As a player, you need to use your mouse to control the position of a thief. Your goal is to collect coins in order to earn score.
Instructions:
//Final Project
//Yinjie Tian
//yinjiet@andrew.cmu.edu
//Section D
var theif;
var cop;
var copX = [];
var copY = [];
var dx = [];
var dy = [];
var coinX = 300;
var coinY = 300;
var coin;
var count = 0;
var carX;
var carX2;
var carY;
var carY2;
var carSpeed;
var showText = false;
function preload(){
thief = loadImage("https://i.imgur.com/lcp6pIM.png");
cop = loadImage("https://i.imgur.com/ndxH6Uh.png");
coin = loadImage("https://i.imgur.com/fKFvpra.png");
}
function setup(){
createCanvas(600, 480);
imageMode(CENTER);
//creating two cars moving in opposite direction
carX = 200;
carX2 = 350;
carY = 0;
carY2 = height - 60;
carSpeed = random(1,5);
// Randomly select cops' starting location and speed
for (var i = 1; i < 15; i++) {
copX[i] = random(30, width - 30);
copY[i] = random(40, height - 40);
dx[i] = random(-2, 5);
dy[i] = random(-2, 5);
}
}
function draw(){
background("grey");
//street background
fill("white");
noStroke();
rect(0,0,100,150);
rect(0,330,100,150);
rect(500,0,100,150);
rect(500,330,100,150)
//crosswalks
rect(110, 50, 20, 100);
rect(150, 50, 20, 100);
rect(190, 50, 20, 100);
rect(230, 50, 20, 100);
rect(270, 50, 20, 100);
rect(310, 50, 20, 100);
rect(350, 50, 20, 100);
rect(390, 50, 20, 100);
rect(430, 50, 20, 100);
rect(470, 50, 20, 100);
rect(110, 330, 20, 100);
rect(150, 330, 20, 100);
rect(190, 330, 20, 100);
rect(230, 330, 20, 100);
rect(270, 330, 20, 100);
rect(310, 330, 20, 100);
rect(350, 330, 20, 100);
rect(390, 330, 20, 100);
rect(430, 330, 20, 100);
rect(470, 330, 20, 100);
//cars moving
fill("red");
rect(carX, carY, 40, 60);
carY += carSpeed;
if(carY > height){
carY = -60;
}
fill("blue");
rect(carX2, carY2, 40, 60);
carY2 -= carSpeed;
if(carY2 < -60){
carY2 = height;
}
// Make the cops move randomly in the canvas
for (var i = 1; i < 8 ; i ++){
image(cop, copX[i], copY[i]);
copX[i] += dx[i];
copY[i] += dy[i];
// bounce back if cops hit boundary
if (copX[i] + 30 > width || copX[i] - 30 < 0){
dx[i] =- dx[i];
}
if (copY[i] + 40 > height || copY[i] - 40 < 0){
dy[i] =- dy[i];
}
// if theif got caught
if (copX[i] > mouseX - 15 & copX[i] < mouseX + 15){
if (copY[i] > mouseY - 20 && copY[i] < mouseY + 20){
endGame();
}
}
// if theif got hit by car1
if (carX > mouseX - 15 & copX < mouseX + 15){
if (carY > mouseY - 20 && carY < mouseY + 20){
endGame();
}
}
// if theif got hit by car2
if (carX2 > mouseX - 15 & carX2 < mouseX + 15){
if (carY2 > mouseY - 20 && carY2 < mouseY + 20){
endGame();
}
}
}
// create theif
image(thief, mouseX, mouseY);
// randomly placing coin
image(coin, coinX, coinY);
// scoreboard
textSize(20);
fill("white");
text("SCORE: " + str(count), 260, 30);
// if theif gets the coin
if (coinStolen()){
coinPlace();
count +=10;
}
}
function coinPlace(){
coinX = random(30, width - 30);
coinY = random(30, height - 30);
}
function coinStolen(){
var d = dist(mouseX, mouseY, coinX, coinY);
if(d < 20){
return true;
}
else {
return false;
}
}
function endGame(){
showText = true;
fill("pink");
textSize(50);
textStyle(BOLD);
textFont('New Roman');
text("GGWP! Please Refresh", 50, height/2);
noLoop();
}
]]>var renderer;
var starSize = 10;
var stars = [];
var launchSpeed = 40;
var starDuration = 1000;
var starLimit = 10;
var starGrowth = .5;
var starMoveFade = 20;
var persX = 30;
var persY = 30;
var timerMultiplier = 0.2;
var particles = [];
var particleSize = 5;
var particleSpeed = 2;
var limitZ = -7500;
var starWiggle = 4;
var bgStars = [];
var bgStarNumber = 100;
function setup() {
renderer = createCanvas(windowWidth, windowHeight, WEBGL);
for (var i = 0; i < 100; i++) {
bgStars.push(makeBackgroundStars());
bgStars[i].x = random(-15000, 16000);
}
frameRate = 60;
}
function draw() {
background(0);
fill(255);
translate(-width / 2, -height / 2, 0);
noCursor();
ellipse(mouseX, mouseY, 25);
//drawing background stars
if (bgStars.length < bgStarNumber) {
bgStars.push(makeBackgroundStars());
}
for (var i = 0; i < bgStars.length; i++) {
bgStars[i].draw();
bgStars[i].move();
if (bgStars[i].x < -15000) {
bgStars.splice(i,1);
}
}
//drawing particles
if (mouseIsPressed) {
particles.push(makeParticle());
for (var i = 0; i < particles.length; i++) {
particles[i].draw();
particles[i].move();
particles[i].remove();
if (particles[i].opq == 0){
particles.splice(i,1);
}
}
}
//drawing stars
for (var i = 0; i < stars.length; i++) {
stars[i].draw();
stars[i].count();
stars[i].move();
if (stars[i].timer > starDuration) {
stars.shift();
}
if (stars[i].x < -15000) {
stars.splice(i,1);
}
}
//removeStars
if (stars.length > starLimit) {
stars.shift();
}
}
//when the mouse is pressed, it starts creating a star
function mousePressed() {
stars.push(makeStar());
}
//as soon as the stars are done being created, they are not the newest
function mouseReleased() {
for (var j = 0; j < stars.length; j++) {
stars[j].newest = false;
}
particles = [];
}
function makeStar() {
var star = {x: mouseX, y: mouseY, z: 0,
size: starSize, newest: true,
perspectiveX: width/2 - mouseX,
perspectiveY: height/2 - mouseY,
// evolve: evolveStar,
count: countTimeStar, timer: 0,
flashX: mouseX, flashY: mouseY, flashZ: -1000,
draw: drawStar, move: moveStar, sizeDown: 20}
return star;
}
//drawing the star
//controls the growth of the star
function drawStar() {
// translate(this.x, this.y, this.z);
push();
translate(this.x, this.y, this.z);
strokeWeight(0);
stroke(200);
//radiance shown by multiple circle
for (var i = 0; i < 3; i++) {
fill(255, 255, 255, 40);
sphere(this.size * (1 + (i / 2)), 15, 15);
}
pop();
if (mouseIsPressed & this.newest == true) {
this.size += starGrowth;
}
if (mouseReleased) {
strokeWeight(0);
push();
translate(this.flashX, this.flashY, 0);
fill(255, 255, 255, 100 - 5 * (this.timer))
sphere(this.size * ((this.timer) ^ 2 / 10));
// sphere((this.size * ((this.timer)/10))/2 * 10);
pop();
}
}
//controls the movement of the star
function moveStar() {
//if it has been released,
if (this.newest == false) {
if (this.z <= limitZ) {
this.y += starWiggle * sin(millis()/300);
this.x -= starMoveFade;
while (this.sizeDown > 1) {
this.size = this.size * .99;
this.sizeDown -= 1;
print("hi")
}
}
else if (this.z > limitZ) {
this.z -= launchSpeed * this.timer * .25;
this.x -= this.perspectiveX / persX * (this.timer * timerMultiplier);
this.y -= this.perspectiveY / persY * (this.timer * timerMultiplier);
}
else {this.y -= launchSpeed * (this.timer * .05);
}
}
}
function countTimeStar() { //works!
if (frameCount % 2 == 0 & this.newest == false) {
this.timer++;
}
}
//creating particles that will gather towards the touch point
function makeParticle() {
var particle = {OriginX: mouseX, OriginY: mouseY, OriginZ: 0,
awayX: mouseX - random(-500, 500),
awayY: mouseY - random(-500, 500),
awayZ: 0 + random(-200, 200), opq: 20,
move: moveParticle, count: countTimeParticle,
draw: drawParticle, remove: removeParticle,
timer: 0}
return particle;
}
function drawParticle() {
push();
translate(this.awayX, this.awayY, this.awayZ);
fill(255, 255, 255, this.opq);
sphere(particleSize);
sphere(particleSize / 2);
pop();
}
function removeParticle() {
if (dist(this.OriginX, this.OriginY, this.OriginZ,
this.awayX, this.awayY, this.awayZ) <= 50) {
this.opq = 0;
}
}
function moveParticle() {
var distX = this.OriginX - this.awayX;
var distY = this.OriginY - this.awayY;
var distZ = this.OriginZ - this.awayZ;
this.awayX += distX * .03;
this.awayY += distY * .03;
this.awayZ += distZ * .03;
this.opq += 50 / dist(this.OriginX, this.OriginY, this.OriginZ,
this.awayX, this.awayY, this.awayZ);
}
function countTimeParticle() {
if (frameCount % 2 == 0 & this.newest == false) {
this.timer++;
}
}
function makeBackgroundStars() {
var bgStar = {x: 14000, y: random(-5000, 5000), z: limitZ,
move: moveBackgroundStars, draw: drawBackgroundStars,
size: random(20, 60), fluctuate: random(400, 800)}
return bgStar;
}
function moveBackgroundStars() {
this.x -= starMoveFade;
this.y += 2 * sin(millis() / this.fluctuate);
}
function drawBackgroundStars() {
push();
translate(this.x, this.y, this.z);
noStroke();
sphere(this.size);
fill(255, 255, 255, 30 * (sin(millis() / this.fluctuate) / 2));
sphere(2 * this.size);
pop();
}
I created an interactive star generator as a simulation for the design project, “Tesla’s Sunlit Night”. The concept is that people entering this brand pop-up shop will be able to interactive the inner walls the way this visualization allows the audience to. The only major difference in the interaction would be the clicks translated as touches.
It is meant to emphasize through experience what Tesla’s solar energy products can do. The reason this pop up is called, “Sunlit Night” is because the experience of creating stars in the dark ceiling , representing the night sky will be powered by the solar energy.
To interact, just click anywhere on the screen. The longer you hold, it will increase in size. I wanted to push further in the growth of star and how each differ in their appearance, but it was computationally too expensive, and could not be realized.
]]>Directions:
Use your mouse you glide the paddle to save the ball from dropping.
colorful cubes will be dropping at the consistent timed rate, make sure to hit the brick with the ball to increase count.
When you hit the ball, you get one point count.
For a challenge, click on the screen to add more balls, but you must balance all to save the game.
Im pretty happy with how this turned out, I definetly used almost everything I knew or saw in the course. It was really fun to make a remix of brick breaker and I learned even more along the way. I was definetly fun to recreate my child hood game.
//Zee Salman
//SECTION E
var gravity = 0.3; // downward force
var springy = 0.2; // velocity
var drag = 0.0001; // drag
var np = 1; // how many particles
var fp= 1;
var particles = [];
var endgame = false;
var timerValue = 3;
var startButton;
var numberBalls = 0;
var x;
var y;
var count = 0;
var block = {
x: 200,
y: -25,
w: 30,
h: 30,
color: "blue",
}
function particleStep() {
this.x += this.dx;
this.y += this.dy;
if (this.y >= height) { // bounce off bottom
endgame = true;
}
if (this.x > width) { // bounce off right wall
this.dx = -this.dx * springy;
} else if (this.x < 0) { // bounce off left wall
this.dx = -this.dx * springy;
} else if (this.y < 0) { // bounce off top
this.y = -this.y;
this.dy = -this.dy * springy;
}
}
function particleDraw() {
//draws the ball
fill(this.colorR, this.colorG, this.colorB);
ellipse(this.x, this.y, this.size, this.size);
}
// create a ball object
function makeParticle(px, py, pdx, pdy) {
p = {x: px, y: py,
dx: pdx, dy: pdy,
step: particleStep,
draw: particleDraw,
size: 20,
colorR: randomColor(),
colorG: randomColor(),
colorB: randomColor(),
}
return p;
}
//randone color for each ball
function randomColor(){
return (random(0,255));
}
function hitBlock(ball, block) {
//ball characteristics
const ballLeft = ball.x - ball.size/2;
const ballRight = ball.x + ball.size/2;
const ballTop = ball.y - ball.size/2;
const ballBottom = ball.y + ball.size/2;
//block characteristics
const blockLeft = block.x - block.w / 2;
const blockRight = block.x + block.w / 2;
const blockTop = block.y - block.h / 2;
const blockBottom = block.y + block.h / 2;
//check for collision
if (
ballRight >= blockLeft &
ballLeft <= blockRight &&
ballBottom >= blockTop &&
ballTop <= blockBottom
) {
if (ballRight >= blockLeft && ballLeft <= blockLeft) {
return true;
} else if (ballLeft <= blockRight & ballRight >= blockRight) {
return true;
} else if (ballBottom >= blockTop & ballTop <= blockTop) {
return true;
} else if (ballTop <= blockBottom & ballBottom >= blockBottom) {
return true;
}
}
return false;
}
function collide() {
for (let i = 0; i < particles.length; i++) {
//if the ball hits the brick, irt disappears
if(hitBlock(particles[i], block)){
count +=1;
block.y = -300;
block.color = randomColor();
}
}
}
function setup() {
createCanvas(600, 400);
for (var i = 0; i < np; i++) {
// make a particle
var p = makeParticle(80, 20, 7,7);
// push the particle onto particles array
particles.push(p);
}
setInterval(timeIt, 1000);
}
function draw() {
//console.log(count);
background("pink");
//drawing the board
stroke(0);
fill('black');
rectMode(CENTER);
rect(mouseX,(11*height/12)+10,100, 10);
//if the game is not over...
if (endgame == false){
//console.log("Working draw func");
collide();
fill(block.color);
noStroke();
rectMode(CENTER);
rect(block.x, block.y, block.w, block.h);
if (block.y >= (11*height/12)) {
endgame = true;
}
// draw all particles in the particles array
for (var i = 0; i < particles.length; i++) { // for each particle
var p = particles[i];
p.step();
p.draw();
//if the ball touches the board,
//it bounces at a slighlty different angle everytime
if (near(p.x,p.y,p.size)){
p.dx = -p.dx + (PI/3);
p.dy = -p.dy;
springy = 1.01;
push();
translate(width,height);
rotate(PI/3);
p.draw();
p.step();
pop();
if((block.y >= height)){
endgame = true;
}
}
}
//timer to display when the next ball is going to disperse
fill("black");
textStyle(BOLD);
text("Count: " + count, width / 2.3, height / 3);
textStyle(NORMAL);
if (timerValue >= 10) {
fill(0);
textSize(20);
text("0:" + timerValue, width / 2, height / 2);
}
if (timerValue < 10) {
fill(0);
textSize(20);
text('0:0' + timerValue, width / 2, height / 2);
}
if (timerValue == 0) {
if(block.y < 0){
block.y = random(20, 350);
block.x = random(20, 350);
}else{
block.y +=20;
fill(0);
textSize(20);
timerValue = 3;
}
//}
}
//if the game is over...
}else if (endgame == true){
count = 0;
// transperent background
fill(0,0,0,100);
rect(0,0,width*2, height*2);
//Game Over display
fill(0);
rect(width/2, height/2, 200, 70);
fill(255);
textSize(32);
text("Game Over!", width / 2.8, height / 1.9);
//Restart button w/ a hover effect
fill(255);
noStroke();
rect(width/2, height/1.5, 100, 50);
fill(0);
textSize(20);
text("Restart", width / 2.25, height / 1.47);
if ((mouseX > (width/2)-50) & (mouseY < (height/1.5)+25) &&
(mouseX < (width/2)+50 && (mouseY > (height/1.5) - 25))) {
fill("green");
rect(width/2, height/1.5, 100, 50);
rect(width/2, height/1.5, 100, 50);
fill(255);
textSize(20);
text("Restart", width / 2.25, height / 1.47);
}
}
}
function timeIt() {
//timer
if (timerValue > 0) {
timerValue--;
}
}
function mouseClicked() {
//for users that want a challenge, click.
var newp = makeParticle(mouseX, mouseY,
random(4, 6), random(4, 6));
particles.push(newp);
if(endgame == true) {
//if restart button clicked, reset game
if (mouseX > 250 & mouseX < 550 && mouseY < 291 &
mouseY > 241) {
endgame = false;
particles = [];
var p = makeParticle(80, 20, 7,7);
particles.push(p);
timerValue = 3;
block.y = -25;
}
}
}
function near(x,y,size) {
//constant testing to see if the ball is touching the board
if ((block.y + block.h) >= (11*height/12)) {
//count +=1;
block.x = random(20,300);
block.y = -25;
}
if((y + size/2) >= (11*height/12) &
(x >= mouseX-50 && x <= mouseX + 100)) {
return true;
}
else{
return false;
}
}
]]>I decided to take the global warming route that was mentioned for my project. I looked at the 2050 flood map that was offered and started researching some of the areas there. Basically, I wanted to show the amazing places that may be completely lost if something isn’t done to slow/stop the temperature rise.
]]>//Shannon Ha
//sha2@andrew.cmu.edu
//Section D
// Final Project
var soundLogos = [];
var amplitude; //initialize amplitude
var level; //initialize amp level
var rotatePath = 0;
var h;
var dY; // dot x position
var dX; // dot y position
function preload(){ //load sounds
soundLogos[1] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Apple-1-2.wav');
soundLogos[2] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Apple-2-text-2.wav');
soundLogos[4] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Intel-p2.wav');
soundLogos[5] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Microsoft-2-1.wav');
soundLogos[6] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Microsoft-3-1.wav');
soundLogos[7] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Netflix-1.wav')
soundLogos[8] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Nokia-1.wav');
soundLogos[9] = loadSound('https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/Skype-1.wav');
}
function setup() {
createCanvas(300, 300);
amplitude = new p5.Amplitude(); // p5.js sound library for amplitude
}
function draw() {
background(0);
push();
translate(width / 2, height / 2); // centers the epicycloid
drawEpicy();
pop();
drawThreeDots();
drawIntelEllipse();
drawMicroGrid()
}
function keyPressed(){ // assigns the number keys to respective sound files and animations.
if (key == '1'){
soundLogos[1].play();
drawEpicy();
} else if (key == '2'){
soundLogos[2].play();
dY = height / 2; // makes starting position of dot center of canvas
dX = width / 2; // makes starting position of dot center of canvas
drawThreeDots();
} else if (key == '3'){
soundLogos[4].play();
drawIntelEllipse();
} else if (key == '4'){
soundLogos[5].play();
drawMicroGrid();
} else if (key == '5'){
soundLogos[6].play();
} else if (key == '6'){
soundLogos[7].play();
} else if (key == '7'){
soundLogos[8].play();
} else if (key == '8'){
soundLogos[9].play();
}
}
//animation for apple
function drawEpicy() {
var a = 60; // variable that controls the size and curvature of shape
var b = a / 2; // variable that controls the size and curvature of shape
level = amplitude.getLevel(); //takes the value of measured amp level.
h = map(level, 0, 3, 20, 900); // maps amplitude to appropriate value
var ph = h / 2; // links mapped amp value as a variable that controls shape.
fill(h * 5, h * 10, 200); //fills color according to measured amp.
noStroke();
beginShape();
for (var i = 0; i < 100; i ++) { // for loop to draw vertex for epicycloid
var t = map(i, 0, 100, 0, TWO_PI); // radian value.
x = (a + b) * cos(t) - h * cos(ph + t * (a + b) / b);
y = (a + b) * sin(t) - h * sin(ph + t * (a + b) / b);
vertex(x, y); //curve line
}
endShape();
}
//animation for text
function drawThreeDots(){ //draws the three dots that fall
fill(255);
noStroke();
print(h);
ellipse(dX - 50, dY, 25, 25);
ellipse(dX, dY * 1.2, 25, 25);
ellipse(dX + 50, dY * 1.5, 25, 25);
dY += 10; // vertical falling
}
function drawIntelEllipse(){
level = amplitude.getLevel();
let h = map(level, 1, 8, 5, 50);
for (var i = 0; i < 15 ; i++){
var diam = rotatePath - 30 * i; // creates the spin out effect of the ellipse
if (diam > 0){ //pushes each new ellipse to show
noFill();
stroke(0, 113, 197); //intel blue
strokeWeight(2);
ellipseMode(CENTER)
push();
translate(width/8 - 90, height/4 - 10); //position of starting ellipse
rotate(cos(2.0));// rotation angle
ellipse(200, 200, diam / h, 40 / h); // the size of the ellipse is affected by amp.
}
}
rotatePath = rotatePath + 2; // controls the speed of the spin out effect.
}
function drawMicroGrid(){ // suppose to imitate the microsoft grid
level = amplitude.getLevel();
let h = map(level, 1, 8, 20, 200);
noStroke();
rectMode(CENTER);
for (var y = 50; y < height + 50; y += 100) { // nested for loop for tiling
for (var x = 50; x < width + 50; x += 100) {
fill(x, y + 100, h * 5); // color is affected by amp
rect(x , y, h * 3, h * 3); // size is affected by amp
}
}
}
How does it work:
Press all the number keys from 1 to 8 and watch the patterns move and change to familiar sound logos!
(For some reason there are problems when Safari is used to view my project so please use Chrome or Firefox!)
In my proposal, I wanted to do some sort of sound visualization either in a form of a game or something similar to patatap. Sticking to my proposal, I used some iconic sounds that can be recognized through our day to day usage of technology. I realized how easy it is to overlook the importance of how these sounds inform our usage of technology so I ended up creating a sonic art piece that creates patterns according to the amplitude measured through the sound files.
My final project does not quite achieve the level of fidelity I originally intended my sonic art to have as the visuals are a bit too noisy and I want it to have a simple yet sophisticated look. I spent quite a bit of time trying to figure out how to use sound libraries in p5.js and mapping the amplitude to each of the various patterns, so I had a bit of difficulty debugging the whole code.
]]>The goal of my final project was to create some interactive project that is simple but playful. When working on this project I took it very incrementally, building on the previous versions and trying to add more elements or making the previous ones better. As I worked my way through the code, I got more comfortable and became more efficient with the way I wrote it. I enjoyed working this way because I found it a lot less intimidating. I really enjoyed making this project. I think if I wanted to I could continue to add on to this. I think a logical next step could be incorporating sound.
Note: I made the canvas size larger then what wordpress can handle because I liked the look of it being a larger area. Below is a zip file of the full size files. The one on wordpress is basically the same just with a few composition adjustments.
Instructions: just use the mouse to play around with the scene. Type into the input bar and hit enter to change the type displayed on the screen.
//Margot Gersing - Final project - mgersing@andrew.cmu.edu - Section E
//for blob shapes
//object one
var xOne;
var yOne;
var dOne;
var opaCityOne = 120;
var overOne = false;
//object two
var xTwo;
var yTwo;
var dTwo;
var opaCityTwo = 120;
var overTwo = false;
//object three
var xThree;
var yThree;
var dThree;
var opaCityThree = 110;
var overThree = false;
//object four
var xFour;
var yFour;
var dFour;
var opCityFour = 110;
var overFour = false;
//object five
var xFive;
var yFive;
var dFive;
var opCityFive = 110;
var overFive = false;
//snake -- code refrenced and modified from p5js examples
//https://p5js.org/examples/interaction-follow-3.html --- link to code refrenced
var snakeX = []; //arrays for snake
var snakeY = [];
var snakeJoint = 10; //amount of joints
var snakeLength = 10; //length between
for (let i = 0; i < snakeJoint; i++) { //loading the joints and lenght into to x and y arrays
snakeX[i] = 0;
snakeY[i] = 0;
}
//for "pong" letters on screen
var letterString = "hello!"; //starting string
var playArray = []; //store the objects (letters and their movements)
var d = [-1, 1]; //direction of array
var input; //for typing
function setup() {
createCanvas(800, 600);
noStroke();
//for type
textFont("Courier New"); //type style
textSize(60); //typesize
//for input bar
input = createInput(); //create the bar to type into
input.position(50, 20);
//for bouncing type, put string into array
for(var i = 0; i < letterString.length; i++){ //load array with objects
var x = map(i, 0, letterString.length, 100, width - 100); //map letters to begin
var vvx = random(1, 5) * d[round(random(0, 1))]; //random velocity in x direction
var vvy = random(1, 5) * d[round(random(0, 1))]; //random velocity in y direction
playArray[i] = createLetter(x, width/2, letterString.charAt(i), vvx, vvy) //call object
}
}
function draw() {
background(250, 120, 110);
//call blob shapes
thingOne();
thingTwo();
thingThree();
thingFour();
thingFive();
//for snake
stroke(87, 156, 128);
strokeWeight(10);
dragSnake(0, mouseX, mouseY); //make snake move with mouse
for (let i = 0; i < snakeX.length - 1; i++) { //create the moevment quality for the snake
dragSnake(i + 1, snakeX[i], snakeY[i]);
}
//get the letters to move around
noStroke();
fill("black");
for(var i = 0; i < playArray.length; i++){
var t = playArray[i];
if(dist(mouseX, mouseY, t.x, t.y) < 30){ //when mouse hovers over letter
t.vx = random(1, 5) * d[round(random(0, 1))]; //get new random velocity x
t.vy = random(1, 5) * d[round(random(0, 1))]; //get new random velocity x
}
if(t.x > width -30 || t.x < 30 || t.y > height - 30 || t.y < 30){ //when the letters hit the walls
t.vx = -t.vx; //reverse the direction
t.vy = -t.vy;
}
t.x = t.x + t.vx; //update the location of the letters
t.y = t.y + t.vy;
text(t.letter, t.x, t.y); //display it
}
}
function thingOne(){
//activation circle
xOne = 25; //location
yOne = 100;
dOne = 600; //diameter
// Test if the cursor is over the box
if(dist(mouseX, mouseY, xOne, yOne) < dOne / 2){ //if the mouse is over the activation ellipse -- var over one is true
overOne = true;
if (overOne == true) { //if true, then change value of opacity which chnages fill color of blob
opaCityOne = 200;
fill(250, opaCityOne, 110); //changing the fill
}
} else { //other wise go back to orignal color
if (opaCityOne >= 120) opaCityOne = opaCityOne - 3; //fades out
fill(250, opaCityOne, 110);
overOne = false;
}
drawOne();
}
function drawOne(){ //location and shape of blob in top left
noStroke();
ellipse(25, 100, 620, 700);
ellipse(50, 300, 450, 320);
}
function thingTwo(){ //same as function thingOne but for bottom right blob
xTwo = 650;
yTwo = 600;
dTwo = 500;
// Test if the cursor is over the box
if(dist(mouseX, mouseY, xTwo, yTwo) < dTwo / 2){
overTwo = true;
if (overTwo == true) {
opaCityTwo = 200;
fill(250, opaCityTwo, 110);
}
} else {
if (opaCityTwo >= 120) opaCityTwo = opaCityTwo - 5;
fill(250, opaCityTwo, 110);
overTwo = false;
}
drawTwo();
}
function drawTwo(){ //location and shape of blob in bottom right
noStroke();
ellipse(650, 600, 600, 500);
ellipse(800, 450, 400, 400);
}
function thingThree(){ //same as function thingOne but for top right blob
xThree = 700;
yThree = -20;
dThree = 500;
// Test if the cursor is over the box
if(dist(mouseX, mouseY, xThree, yThree) < dThree / 2){
overThree = true;
if (overThree == true) {
opaCityThree = 255;
fill(250, 120, opaCityThree);
}
} else {
if (opaCityThree >= 110) opaCityThree = opaCityThree - 3;
fill(250, 120, opaCityThree);
overThree = false;
}
drawThree();
}
function drawThree(){ //location and shape of blob in top right
noStroke();
ellipse(700, -20, 550, 300);
}
function thingFour(){ //same as function thingOne but for center blob
xFour = 475;
yFour = 225;
dFour = 200;
// Test if the cursor is over the box
if(dist(mouseX, mouseY, xFour, yFour) < dFour / 2){
overFour = true;
if (overFour == true) {
opCityFour = 255;
fill(250, 120, opCityFour);
}
} else {
if (opCityFour >= 110) opCityFour = opCityFour - 3;
fill(250, 120, opCityFour);
overFour = false;
}
drawFour();
}
function drawFour(){ //location and shape of blob in center
noStroke();
ellipse(475, 225, 225, 200);
}
function thingFive(){ //same as function thingOne but for bottom left
xFive = 150;
yFive = 600;
dFive = 200;
// Test if the cursor is over the box
if(dist(mouseX, mouseY, xFive, yFive) < dFive / 2){
overFive = true;
if (overFive == true) {
opCityFive = 255;
fill(250, 120, opCityFive);
}
} else {
if (opCityFive >= 110) opCityFive = opCityFive - 3;
fill(250, 120, opCityFive);
overFive = false;
}
drawFive();
}
function drawFive(){ //location and shape of blob in bottom left
noStroke();
ellipse(150, 600, 225, 200);
}
function dragSnake(i, xin, yin) { // for snake
const dx = xin - snakeX[i];
const dy = yin - snakeY[i];
const angle = atan2(dy, dx);
snakeX[i] = xin - cos(angle) * snakeLength;
snakeY[i] = yin - sin(angle) * snakeLength;
joint(snakeX[i], snakeY[i], angle);
}
function joint(x, y, a) { //for snake
push();
translate(x, y);
rotate(a);
line(0, 0, snakeLength, 0);
pop();
}
function createLetter(x, y, letter, vx, vy){ //object for each letter from the array, with loction, velocity
return{x: x, y: y, letter: letter, vx: vx, vy: vy}
}
function keyPressed(){ //when hit enter key call word function
if(keyCode == ENTER) word();
}
function word() { //for changing the letters on the screen
playArray = []; //empty array that holds letters from string
letterString = input.value(); //make the value of the input the new string (what you type)
//print(input.value());
//reload the newstring into the array
for(var i = 0; i < letterString.length; i++){ //load array with objects
var x = map(i, 0, letterString.length, 100, width - 100); //map letters to begin
var vvx = random(1, 5) * d[round(random(0, 1))]; //random velocity
var vvy = random(1, 5) * d[round(random(0, 1))];
playArray[i] = createLetter(x, width/2, letterString.charAt(i), vvx, vvy) //call object
}
}
]]>