Jasmine Lee – Final Project

sing

//Jasmine Lee
//jasmine4@andrew.cmu.edu
//Section C
//Final Project

var nodes = []; //array to hold node objects
var node1c = 1; //node sound counters
var node2c = 1;
var node3c = 1;
var node4c = 1;
var node5c = 1;
var node6c = 1;
var node7c = 1;
var node8c = 1;
var node9c = 1;
var node10c = 1;
var waves; //sound variables
var windchimes;
var rain;
var campfire;
var chant;
var crickets;
var birdwhistle;
var cafe;
var church;
var stream;
var c1; //gradient colors
var c2;
var x1; //gradient controls
var inter;
var c;
var xarray = []; //arrays to hold bubble positions
var yarray = [];
var ydir = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
var r = 0; //bubble colors
var g = 0;
var b = 0;
var bubbY; //controls bubblesNC movement
var bubbY2;
var h; //time
var m;
var s;

function preload() {
    waves = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/waves.mp3")
    windchimes = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/windchimes.wav")
    rain = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/rain.wav")
    campfire = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/campfire.wav")
    chant = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/chant.mp3")
    crickets = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/crickets.wav")
    birdwhistle = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/birdwhistle.wav")
    cafe = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/cafe.m4a")
    church = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/church.wav")
    stream = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/12/stream.wav")
}

function setup() {
    createCanvas(600, 450);
    background(255);

    //creates node objects and gives them parameters
    nodes = [{x: 70, y: 70, d: 40}, //top row of nodes
             {x: 230, y: 120, d: 90},
             {x: 390, y: 75, d: 50},
             {x: 520, y: 130, d: 40},
             {x: 125, y: 235, d: 50}, //middle row of nodes
             {x: 400, y: 230, d: 80},
             {x: 550, y: 270, d: 30}, //bottom row of nodes
             {x: 80, y: 380, d: 80}, 
             {x: 250, y: 330, d: 40},
             {x: 450, y: 370, d: 50},
             ]

    //shows the nodes initially when page is refreshed
    for (var i = 0; i < nodes.length; i ++) {
        fill(200);
        noStroke();
        ellipse(nodes[i].x, nodes[i].y, nodes[i].d)
        }
}

function draw() {
    //gradient background
    c1 = color(255, 255, 255);
    c2 = color(220 + (mouseX * 0.04), 240, 255);
    setGradient(c1, c2);

    //functions that control whether the nodes are colored/white
    n1a();
    n2a();
    n3a();
    n4a();
    n5a();
    n6a();
    n7a();
    n8a();
    n9a();
    n10a();

    //bubbles that follow the mouse
    cursorP();

    //bubbles controlled by clock
    bubblesNC();

    //text
    motivationalText();
}

function mousePressed() {
    //functions that control whether the nodes play/pause sounds
    n1s();
    n2s();
    n3s();
    n4s();
    n5s();
    n6s();
    n7s();
    n8s();
    n9s();
    n10s();
}

function mouseDragged() {
    //adds mouse old coordinates into bubble arrays to create new bubbles
    xarray.push(mouseX)
    yarray.push(mouseY)
}

function setGradient(c1, c2) {
    //creates interactive background gradient
    noFill();
    for (var y = 0; y < height; y++) {
        var inter = map(mouseY, 0, height, 0, 1);
        var c = lerpColor(c1, c2, inter);
        stroke(c);
        line(0, y, width, y);
    }
}

//node 1 appearance
function n1a() { 
    noStroke();
    if (node1c % 2 == 0) {
        fill(255);
    } else {
        fill(245, 204, 240); //periwinkle
    }
    ellipse(70, 70, 40, 40);
}

//node 1 sound
function n1s() { 
    if (mouseX > 50 & mouseX < 90 && mouseY > 50 & mouseY < 90) {
        node1c = node1c + 1;
        if (node1c % 2 == 0) {
            waves.loop();
        } else {
            waves.pause();
        }
    } 
}

//node 2 appearance
function n2a() { 
    if (node2c % 2 == 0) {
        fill(255);
    } else {
        fill(233, 255, 255); //robin's egg blue
    }
    ellipse(230, 120, 90, 90);
}

//node 2 sound
function n2s() { 
    if (mouseX > 185 & mouseX < 275 && mouseY > 75 & mouseY < 165) {
        node2c = node2c + 1;
        if (node2c % 2 == 0) {
            windchimes.loop();
        } else {
            windchimes.pause();
        }
    }
}

//node 3 appearance
function n3a() {
    if (node3c % 2 == 0) {
        fill(255);
    } else {
        fill(217, 240, 255); //light blue
    }
    ellipse(390, 75, 50, 50);
}

//node 3 sound
function n3s() {
    if (mouseX > 365 & mouseX < 415 && mouseY > 50 && mouseY < 100) {
        node3c = node3c + 1;
        if (node3c % 2 == 0) {
            rain.loop();
        } else {
            rain.pause();
        }
    }
}

//node 4 appearance
function n4a() {
    if (node4c % 2 == 0) {
        fill(255);
    } else {
        fill(246, 224, 252); //light pink-purple
    }
    ellipse(520, 130, 40, 40);
}

//node 4 sound
function n4s() {
    if (mouseX > 500 & mouseX < 540 && mouseY > 110 & mouseY < 150) {
        node4c = node4c + 1;
        if (node4c % 2 == 0) {
            campfire.loop();
        } else {
            campfire.pause();
        }
    }
}

//node 5 appearance
function n5a() {
    if (node5c % 2 == 0) {
        fill(255);
    } else {
        fill(217, 195, 242); //light purple
    }
    ellipse(125, 235, 50, 50);
}

//node 5 sound
function n5s() {
    if (mouseX > 100 & mouseX < 175 && mouseY > 210 & mouseY < 260) {
        node5c = node5c + 1;
        if (node5c % 2 == 0) {
            chant.loop();
        } else {
            chant.pause();
        }
    }
}

//node 6 appearance
function n6a() {
    if (node6c % 2 == 0) {
        fill(255);
    } else {
        fill(241, 223, 242); //pale pink
    }
    ellipse(400, 230, 80, 80);
}

//node 6 sound
function n6s() {
    if (mouseX > 360 & mouseX < 440 && mouseY > 190 & mouseY < 270) {
        node6c = node6c + 1;
        if (node6c % 2 == 0) {
            crickets.loop();
        } else {
            crickets.pause();
        }
    }
}

//node 7 appearance
function n7a() {
    if (node7c % 2 == 0) {
        fill(255);
    } else {
        fill(189, 220, 255); //baby blue
    }
    ellipse(550, 270, 30, 30);
}

//node 7 sound
function n7s() {
    if (mouseX > 535 & mouseX < 565 && mouseY > 255 & mouseY < 285) {
        node7c = node7c + 1;
        if (node7c % 2 == 0) {
            birdwhistle.loop();
        } else {
            birdwhistle.pause();
        }
    }
}

//node 8 appearance
function n8a() {
    if (node8c % 2 == 0) {
        fill(255);
    } else {
        fill(238, 210, 242); //mauve
    }
    ellipse(80, 380, 80, 80);
}

//node 8 sound
function n8s() {
    if (mouseX > 40 & mouseX < 120 && mouseY > 340 & mouseY < 420) {
        node8c = node8c + 1;
        if (node8c % 2 == 0) {
            cafe.loop();
        } else {
            cafe.pause();
        }
    }
}

//node 9 appearance
function n9a() {
    if (node9c % 2 == 0) {
        fill(255);
    } else {
        fill(235, 154, 240); //light blue-purple
    }
    ellipse(250, 330, 40, 40);
}

//node 9 sound
function n9s() {
    if (mouseX > 230 & mouseX < 270 && mouseY > 310 & mouseY < 350) {
        node9c = node9c + 1;
        if (node9c % 2 == 0) {
            church.loop();
        } else {
            church.pause();
        }
    }
}

//node 10 appearance
function n10a() {
    if (node10c % 2 == 0) {
        fill(255);
    } else {
        fill(206, 228, 237); //pale blue
    }
    ellipse(450, 370, 50, 50);
}

//node 10 sound
function n10s() {
    if (mouseX > 425 & mouseX < 475 && mouseY > 345 & mouseY < 395) {
        node10c = node10c + 1;
        if (node10c % 2 == 0) {
            stream.loop();
        } else {
            stream.pause();
        }
    }
}

//controls cursor generated bubbles and their movement
function cursorP() {
    for (var i = 0; i < xarray.length; i ++) {
        //gives floating bubbles flashing colors
        r = random(220, 255);
        g = random(220, 255);
        b = random(220, 255);
        fill(r, g, b);

        //creates bubbles when mouse is dragged
        ellipse(xarray[i], yarray[i], i, i)

        //makes bubbles bounce off bottom of canvas
        if (yarray[i] > (450 - (i / 2))) {
            ydir[i] = -(ydir[i]);
            yarray[i] = (450 - (i / 2)) - 1;
        } else {
            yarray[i] = yarray[i] + ydir[i]; 
        }

        //makes bubbles bounce off top of canvas
        if (yarray[i] < (i / 2)) {
            ydir[i] = -(ydir[i]);
            yarray[i] = (i / 2) - 1;
         } else {
            yarray[i] = yarray[i] + ydir[i];
        }

        //makes bubbles bounce off nodes
        for (var j = 0; j < nodes.length; j ++) {
            if ((dist(xarray[i], yarray[i], nodes[j].x, nodes[j].y)) < (((nodes[j].d) / 2) + (i / 2))) {
                ydir[i] = -(ydir[i]);
                if (ydir[i] > 0) {
                    //lets bubbles bounce off bottom of nodes
                    yarray[i] = yarray[i] + (i / 2) + 1; 
                } else {
                    //lets bubbles bounce off top of nodes
                    yarray[i] = yarray[i] - (i / 2) - 1; 
                }
            }
        }
    }

    //deletes bubbles if there are more than 25
    if (xarray.length > 25) {
        xarray.shift();
        yarray.shift();
    }
}

function bubblesNC() {
    h = hour();
    m = minute ();
    s = second ();

    //moves 7.5 pixels down for every second that passes
    bubbY = s * 7.5;
    bubbY2 = 450 - (s * 7.5);

    noStroke();
    //white bubbles
    fill(255, 255, 255, 100);
    ellipse(70, bubbY, 200, 200);
    ellipse(200, bubbY + 20, 80, 80);
    ellipse(450, bubbY - 40, 320, 320);
    ellipse(300, bubbY2, 80, 80);
    ellipse(30, bubbY2, 130, 130);
    ellipse(520, bubbY + 5, 100, 100);
    ellipse(370, bubbY2 - 15, 220, 220);
}

function motivationalText() {
    //adds text to center of the screen
    textAlign(CENTER, CENTER);
    textSize(30);
    textStyle(BOLDITALIC);
    fill(255, 255, 255);
    text('hello', 300, 195);
    fill(255, 255, 255);
    text('hello', 300, 225);
    fill(255, 255, 255, 200);
    text('hello', 300, 255);

}

For my final project, I intended to create a dreamlike atmosphere. The sounds that the nodes play are a mystery, with the user having to click them to discover what they are. The project acts as a sort of music sampler to allow the user to play whatever tracks they’d like to hear at the same time. Once the music is on, the node disappears into the white background, with the user having to interact with the color changing background to find the node again. When the mouse is dragged, many bubbles are created that bounce around the canvas and off the music nodes to create visual interest for the user. When all the sounds are being played and the mouse is used to make the background white, an interesting “screensaver” is created with the negative space.

Sean Leo_Final Project

TEST CARD GENERATOR

The Test Card Generator (TCG) allows you to create a customizable Test pattern to use for testing outputs for a media installation. You can select HD or SD (1920×1080 or 1280×720) which will populate on your card. Then using the input fields you can type in what you’d like the card to say. Provided is a field for a title and labeling the output and input; a Projector using SDI, for example. You can also color the grid lines to further customize and is extremely helpful with multiple outputs. Un-checking the boxes will take away some of the graphic elements to further customize the look of the card. Lastly clicking save will save a PNG titled with the name and selected resolution to your downloads folder.

As a media designer, I’m often faced with ambitious projects and installations that call for multiple outputs and sources of media. In a room with wrap around projections seeing the same test pattern everywhere doesn’t help you understand how your system is working and what is media is being feed to what. A tool like TCG allows me to quickly test multiple output sources and customize the look based on version, show, or whatever I feel like I need shown.

Below are some of the customizable test cards I generated:

thisatestcard_1280x720.png
WALL1of4_1920x1080.png
TESTCARDGENERATOR_1920x1080.png
test_1920x1080.png

sleo_finalProject_20191205

//Sean B. Leo
//sleo@andrew.cmu.edu
//Section C 
//FINAL PROJECT

//TEST CARD GENERATOR___________(c) Sean B. Leo 2019
/*The TCG allows you to create a customizable Test pattern 
to use for testing outputs for a media installion. You can 
select HD or SD (1920x1080 or 1280x720) which will populate on your card.
Then using the input fields you can type in what you'd like the card to say.
Provided is a field for a title and labeling the output and input; 
a Projector using SDI for example. You can also color the grid lines to further
customize and is extremly helpful with multiple outputs. 
Un-checking the boxes will take away some of the graphic elements
to further customize the look of the card. 
Lastly clicking save will save a PNG titled with the name and selected resolution 
to your downloads folder.*/

//Global variables
//aspect ratio
var aspectX = 16;
var aspectY = 9;
// grid color variables
var colorInp1, colorInp2;
//gradient color variables
var c1, c2;
//grid slider
var gridSlider;
var spacing = 0;
//element dimensions
var colW;
var colH;
var rowW;
var rowH;
//radio varibile
var radio;


function setup() {
//radio options set for HD and SD    
radio = createRadio(); 
radio.option('1920x1080');// HD
radio.option('1280x720');// SD
//canvas sized to fit within WP window
createCanvas(600, 337.5);
colorMode(RGB);
//Color picker input for elements
colorInp1 = createColorPicker('#ffffff'); //set to white at start
colorInp1.position(360,height+30);
colorInp2 = createColorPicker('#727272'); //set to gray at start
colorInp2.position(420,height+30);
colorInp3 = createColorPicker('#ffffff'); //set to white at start
colorInp3.position(480,height+30);
//black and white gradient color  
c1 = color(0);
c2 = color(255);
//Title for test card
textInp1 = createInput('NAME YOUR TEST CARD');
textInp1.size(150, 20);
textInp1.position(0,height+30);
//label output (projector, screen, etc.)
textInp2 = createInput('OUTPUT');
textInp2.size(100, 20);
textInp2.position(150,height+30);
//label input (HDMI, DVI, SDI, etc.)
textInp3 = createInput('INPUT');
textInp3.size(100, 20);
textInp3.position(250,height+30);
//Save custom test card
button = createButton('Save Test Card');
button.position(420, height+60);
button.mousePressed(saveImage);
//graphic element sizing
colW = width/2.28/8;
colH = height/3;
barStartX = width/3.56;
barStartY = height/6;  
//turn off or on elements
toggleGrid = createCheckbox('Grid', true);//set as on from start
toggleGrid.changed(toggleSet);
toggleGrid.position(0, height+60);

toggleLines = createCheckbox('Lines', true);
toggleLines.changed(toggleSet);
toggleLines.position(60, height+60);

toggleColor = createCheckbox('Color Bars', true);
toggleColor.changed(toggleSet);
toggleColor.position(120, height+60);

toggleGrad = createCheckbox('Black and White', true);
toggleGrad.changed(toggleSet);
toggleGrad.position(210, height+60);
}
function saveImage(){    
radioXY = radio.value(); // read radio value as variable
var title = textInp1.value() +"_" + radioXY; //set file name from custom inputs
if (button.mousePressed()){
    saveCanvas(title,'png');
    }
}
function draw() {
background(0);
toggleSet();
textBlocks();
}
function toggleSet(){
//turn off or on element functions based on state of checkbox    
if (toggleGrid.checked()) {
  grid();
  }
if (toggleLines.checked()) {
  lines();
  }
if (toggleColor.checked()) {
  colorBars();
  } 
if (toggleGrad.checked()){
  gradient();
  }
}
function grid(){
//draw grid    
var gridColorTop = colorInp1.color();//set grid color based on selection
var gridColorBot = colorInp2.color();//set grid color based on selection
var gridStrokeTop = 2;
var gridStrokeBot = .5
var x = spacing;
var y = spacing;
//bottom grid loop
for (var x = 0; x < width; x += width / (aspectX*2)) {
  for (var y = 0; y < height; y += height / (aspectY*2)) {
    stroke(gridColorBot);
    strokeWeight(gridStrokeBot);
    line(x, 0, x, height);
    line(0, y, width, y);
    }
  }
//top grid
for (var x = 0; x < width; x += width / aspectX) {
  for (var y = 0; y < height; y += height / aspectY) {
    stroke(gridColorTop);
    strokeWeight(gridStrokeTop);
    line(x, 0, x, height);
    line(0, y, width, y);
    }
  }
}
function lines(){    
var lineColor = colorInp3.color();//set color based on selection
stroke(lineColor);
strokeWeight(2);
//diagonals
line(0, 0, width, height);
line(width, 0, 0, height);
noFill();
//cross lines
line(width/2, 0, width/2, height);   
line(0, height/2, width, height/2); 
//circle
ellipse(width/2, height/2, width/1.8);
}
function colorBars(){
//SMPTE color bars
noStroke();
fill('white');
rect(barStartX, barStartY, colW, colH);
fill('yellow');
rect(barStartX+colW, barStartY, colW, colH);
fill('cyan');
rect(barStartX+colW*2, barStartY, colW, colH);
fill(0, 255, 0);
rect(barStartX+colW*3, barStartY, colW, colH);
fill('magenta');
rect(barStartX+colW*4, barStartY, colW, colH);
fill('red');
rect(barStartX+colW*5, barStartY, colW, colH);
fill('blue');
rect(barStartX+colW*6, barStartY, colW, colH);
fill('black');
rect(barStartX+colW*7, barStartY, colW, colH);
}
function setGradient(x, y, w, h, c1, c2) {
//creates gradient    
noFill();
for (var i = x; i <= x + w; i++) {
  var inter = map(i, x, x + w, 0, 1);
  var c = lerpColor(c1, c2, inter);
  stroke(c);
  line(i, y, i, y + h);
  }
}
function gradient(){
//gradient block
//calls gradient and creates shape
setGradient(barStartX, height/2, colW*8, colH/4, c1, c2);
//grayscale blocks
noStroke();
fill(0);
rect(barStartX, height/1.779, colW*2, colH/6);
fill(255/4);
rect(barStartX+colW*2, height/1.779, colW*2, colH/6);
fill(255/2);
rect(barStartX+colW*4, height/1.779, colW*2, colH/6);
fill('white');
rect(barStartX+colW*6, height/1.779, colW*2, colH/6);
}
function textBlocks() {
radioXY = radio.value();
fill(255);
textSize(30);
textAlign(CENTER, CENTER);
stroke(27);
strokeWeight(5);//set against grid pattern for better legibility
//takes in first text value to display at top of canvas
text(textInp1.value(), width/2, barStartY-barStartY/4);
strokeWeight(4);
//textSize(18);
//takes in radio button value to set text on canvas
textSize(18);
text(radioXY, width/2 - colW*2.5, barStartY*4.35);
//second text value 'OUTPUT'
textSize(18);
text(textInp2.value(), width/2, barStartY*4.35);
//third text value 'INPUT
textSize(18);
text(textInp3.value(), width/2 + colW*2.5, barStartY*4.35);
//Signing my work
textSize(10);
fill('yellow');
text('(c) Sean B. Leo 2019', width-colW-20, height-10);
}

Hyejo Seo – Final Project

sketch

/*
Hyejo Seo
Section A
hyejos@andrew.cmu.edu
Final Project
*/
var ang = 0;
var doorX = 180;
var doorY = 55;
var arcX = 500;
var arcY = 85;
let active;
let activeB;

function setup() {
    createCanvas(600, 400);
    // loading image for green (palace)
    green = loadImage("https://i.imgur.com/AA44Ncy.jpg");
    // loading image for blue (flower field)
    blue = loadImage("https://i.imgur.com/7prQtyF.jpg");
    // loading image for red (sophie's hometown)
    red = loadImage("https://i.imgur.com/puWmVDz.jpg");
    // loading image for yellow (war scene)
    black = loadImage("https://i.imgur.com/yZ2mKQJ.jpg");
    active = 1;
    activeB = 1;
}

function draw() {
    angleMode(DEGREES);
    activeBackground();
    roomSetting();
    activeElement();
    wheel();
    // arrow/pointer
    noStroke();
    fill('#32303A');
    rect(arcX - 4, 0, 8, 30);
    triangle(arcX - 8, 30, arcX + 8, 30, arcX, 45);
    fill('#727072');
    rect(arcX - 2.5, 0, 5, 30);
    triangle(arcX - 6, 30, arcX + 6, 30, arcX, 45);
}
function wheel() {
    // center of the wheel 
    fill(250, 204, 107);
    circle(arcX, arcY, 17);
    // highlight in the middle
    fill(255, 233, 150);
    noStroke();
    beginShape();
    curveVertex(494.5, 87);
    curveVertex(494, 86);
    curveVertex(494.2, 84);
    curveVertex(495, 82);
    curveVertex(497, 80);
    curveVertex(499, 80); 
    curveVertex(497, 82);
    curveVertex(496, 84);
    curveVertex(495.5, 85);
    curveVertex(495, 87);
    curveVertex(495, 85);    
    endShape();

}
function mousePressed() {
    // if user clicks inside of the wheel, it returns true 
    if ((mouseX >= arcX - 120 & mouseX <= arcX + 120) && (mouseY >= arcY - 120 & mouseY <= arcY + 120)) {
            active = ((active % 4) + 1); // for the wheel to turn 
            activeB = active; // for the background to change 
            return true
        } else {
            return false 
    }
}
function roomSetting() {
    //walls 
    noStroke();
    fill("#E8E8E8");
    rect(0, 0, width, 53);
    rect(0, 53, 120, 107);
    rect(0, 53 + 97, 15, 300);
    rect(0, 290, 120, 200);
    rect(415, 53, 190, 107);
    rect(415, 160, 10, 240);
    rect(575, 160, 30, 240);
    rect(420, 300, 155, 100);

    // left window
    fill("#4C3D2E");
    rect(15, 160, 120, 10);
    rect(15, 170, 10, 120);
    rect(15, 290, 120, 10);
    rect(15, 225, 120, 8);
    rect(90, 170, 8, 120);
    // right window
    rect(425, 160, 140, 10);
    rect(425, 170, 10, 120);
    rect(425, 290, 140, 10);
    rect(565, 160, 10, 140);
    rect(495, 170, 10, 120);
    rect(435, 225, 140, 10);

    // door frame
    stroke("#72594E");
    strokeWeight(5);
    noFill();
    rect(175, 55, 240, height);
    // opened door 
    fill("#725B45");
    noStroke();
    quad(doorX, doorY, doorX - 50, doorY - 30, doorX - 50, height, doorX, height);
    stroke("#4C3D2E");
    strokeWeight(2);
    line(doorX - 10, doorY - 5, doorX - 10, height);
    line(doorX - 17, doorY - 9, doorX - 17, height);
    line(doorX - 27, doorY - 15, doorX - 27, height);
    line(doorX - 38, doorY - 21, doorX - 38, height);
    noStroke();
    // thickness of the door 
    fill("#4C3D2E");
    rect(doorX - 60, doorY - 30, 10, height);
}


function blueTop() { // wheel with blue being pointed 
    stroke(0);
    strokeWeight(1);
    // blue 
    fill(39, 154, 241);
    arc(arcX, arcY, 120, 120, 225, 315);
    // black 
    fill(52, 46, 55);
    arc(arcX, arcY, 120, 120, 315, 405);
    //red
    fill(255, 50, 50);
    arc(arcX, arcY, 120, 120, 45, 135);
    // green 
    fill(159, 211, 86);
    arc(arcX, arcY, 120, 120, 135, 225);
    
}
function greenTop() { // wheel with green being pointed
    stroke(0);
    strokeWeight(1); 
    //green 
    fill(159, 211, 86);
    arc(arcX, arcY, 120, 120, 225, 315);
    // blue
    fill(39, 154, 241);
    arc(arcX, arcY, 120, 120, 315, 405);
    //black
    fill(52, 46, 55);
    arc(arcX, arcY, 120, 120, 45, 135);
    // red
    fill(255, 50, 50);
    arc(arcX, arcY, 120, 120, 135, 225);
}
function redTop() { // wheel with red being pointed
    stroke(0);
    strokeWeight(1);
    //red 
    fill(255, 50, 50);
    arc(arcX, arcY, 120, 120, 225, 315);
    // green
    fill(159, 211, 86);
    arc(arcX, arcY, 120, 120, 315, 405);
    //blue
    fill(39, 154, 241);
    arc(arcX, arcY, 120, 120, 45, 135);
    // black
    fill(52, 46, 55);
    arc(arcX, arcY, 120, 120, 135, 225);
}
function blackTop() { // wheel with black being on pointed
    stroke(0);
    strokeWeight(1);
    //black 
    fill(52, 46, 55);
    arc(arcX, arcY, 120, 120, 225, 315);
    // red
    fill(255, 50, 50);
    arc(arcX, arcY, 120, 120, 315, 405);
    //green
    fill(159, 211, 86);
    arc(arcX, arcY, 120, 120, 45, 135);
    // blue
    fill(39, 154, 241);
    arc(arcX, arcY, 120, 120, 135, 225);
}

function activeElement() {
    if (active === 1) { // wheel starts with blue being pointed 
        return blueTop();
    }
    else if (active === 2) {
        return greenTop();
    }
    else if (active === 3) {
        return redTop();
    }
    else if (active === 4) {
        return blackTop();
    }
}

function activeBackground() {
    if (activeB === 1) { //starts with the background for blue
        return background(blue);
    }
    else if (activeB === 2) {
        return background(green);
    }
    else if (activeB === 3) {
        return background(red);
    }
    else if (activeB === 4) {
        return background(black);
    }
}

For this project, I recreated Howl’s door in the animation film, Howl’s Moving Castle. In this movie, the door leads to different countries/places based on the color the pointer is at (wheel). In order to see where this door can lead you to, you click anywhere inside the wheel. As the color the pointer is pointing at in the wheel changes, the background changes. 

Blue – flower field 

Green – palace 

Red – Sophie’s hometown (train)

Black – a war scene 

 

A scene from Howl’s Moving Castle. This was my inspiration.

Raymond Pai – Final Project

sketch

Due to being unable to upload programs with libraries on WordPress, you need to click on the ‘sketch’ hyperlink to enjoy this program.

For my final project, I wanted to expand upon the Raining Letters assignment. I wanted to experiment with the camera more, and I decided to create an application that lets the user draw with their face. Moving your face around lets you draw, pressing the spacebar clears your art. The canvas changes color each time the page loads and is based on halftone art (which has a grid of circles). You can also use the slider to change the thickness of the brush (face brush :0).

The program and the libraries linked to it can be found in this zip file:

rpai_final

Sewon Park – PO – Final

sketch

//Sewon Park
//sewonp@andrew.cmu.edu
//Final Project
//Section B

var counter = 0;
var oceanamp = 100;
var oceanspeed = 0.001;
var x = 150;
var polarbearURL = "https://i.imgur.com/dQOjRSb.png"


function preload() {
    polarbear = loadImage(polarbearURL);
}

function setup() {
    createCanvas(600, 400);
    background(180, 240, 250);
  
    fill(150, 75, 0);
    rect(380, 365, 10, 30);
    rect(440, 365, 10, 30);
    rect(500, 365, 10, 30); //Treetrunks

    fill(0, 255, 0)
    triangle(370, 365, 385, 325, 400, 365);
    triangle(430, 365, 445, 325, 460, 365);
    triangle(490, 365, 505, 325, 520, 365); //Tree Leaves
}

function draw() {
    fill(255, 100, 0);
    rect(400, 30, 100, 50); //button
    
    fill(255);
    textSize(13);
    text("Click", 435, 50); //click text on button

    strokeWeight(2);
	stroke(255);
	line(300, 0, 300, 400); //Divider down the middle

    noStroke();
    fill(255, 204, 51)
    ellipse(150, 100, 30, 30) //sun

    fill(255);
    rect(50, 250, 200, 200); //Iceberg
  
    noFill();
    rect(360, 330, 40, 20);
    rect(420, 330, 40, 20);
    rect(480, 330, 40, 20); //Windows

    ocean();

    imageMode(CENTER);
    image(polarbear, 150, 240, 50, 50);

    if (counter == 1) {
        fire1();
    } 
    if (counter == 2) {
        fire2();
    }
    if (counter == 3) {
        fire3();
    }
    if (counter == 4) {
        factory();
        ocean2(); //Increase water levels afer iceberg sinks
        newsun(); //New sun after factory is built
        textSize(30)
        text("GAME OVER", 210, 200)
    }
}

function ocean() {
    fill(0, 0, 250); 
    noStroke();
    beginShape(); 
    for (var x = 0; x < width/2; x++) {
        var position2 = x * oceanamp + (millis() * oceanspeed);
        var y = map(noise(position2), 0, 10, height/1.4, height); 
        vertex(x, y); 
    }
    vertex(width/2, height);
    vertex(0, height);
    endShape(); //The Ocean
}

function ocean2() {
    fill(0, 0, 250); 
    noStroke();
    beginShape(); 
    for (var x = 0; x < width/2; x++) {
        var position2 = x * oceanamp + (millis() * oceanspeed);
        var y = map(noise(position2), 0, 10, height/2, height); 
        vertex(x, y); 
    }
    
    vertex(width/2, height);
    vertex(0, height);
    endShape(); //The new ocean after the iceberg sinks
}

function newsun() {
    fill(255, 51, 51);
    ellipse(150, 100, 60, 60); //bigger and stronger sun to appear 
}

function factory() {
    fill(100);  
    rect(350, 300, 180, 200); //factory body

    triangle(350, 300, 410, 250, 410, 300); 
    triangle(410, 300, 470, 250, 470, 300);
    triangle(470, 300, 530, 250, 530, 300); //Ceiling
  
    fill(250);
    rect(360, 330, 40, 20);
    rect(420, 330, 40, 20);
    rect(480, 330, 40, 20); //Windows
}

function fire1() {
    fill(255,0,0);
    ellipse(385, 375, 46, 46);
    triangle(361, 375, 385, 310, 409, 375)
    fill(255, 255, 0);
    ellipse(385, 375 ,30 ,30); //fire 1
}

function fire2() {

    fill(255,0,0);
    ellipse(445, 375, 46, 46);
    triangle(421, 375, 445, 310, 469, 375)
    fill(255, 255, 0);
    ellipse(445, 375, 30, 30); //fire 2
}

function fire3() {
    fill(255,0,0);
    ellipse(505,375,46,46);
    triangle(481,375,505,310,529,375);
    fill(255,255,0);
    ellipse(505,375,30,30); //fire 3
}

function mousePressed() {
    if (mouseX < 500 & mouseX > 400 && mouseY < 80 && mouseY > 30 ){
        counter = counter + 1; 
    } //Counter that keeps track of elemets to be appeared when button is clicked
}


  

 







As I initially had trouble selecting a theme for my final project, I decided to follow Professor Dannenburg’s suggestion to make a climate change themed work. As I appreciated art not only for its aesthetics but also for the message it sends to the public, I thought creating a project that sends a message about global warming could be rewarding.

I wanted to show how the actions of humans can have a detrimental impact on the livelihood of polar bears. Although it was already a common topic, I wanted to express that human beings ultimately have the power to preserve or destroy the environment that these animals were dependent on.

As such, I created a “button” that emulated real life actions that caused global warming and the destruction of the ice caps. Each click creates a fire that would burn the trees and finally create a factory. After the action sequence is completed, the player will have destroyed the ozone layer, causing the ice cap to melt and kill the polar bear.

The first stage of the game

The final sequence of the game

Xu Xu & Xiaoyu Kang – Final Project

sketch

// Xiaoyu Kang & Xu (Claire) Xu
// Section B
// xkang@andrew.cmu.edu & xux1@andrew.cmu.edu
// Final Project
var hatShapeX = 130; //BY BOTH XIAOYU AND XU
var hatShapeY = 128;
var heartShapeX = 205;
var heartShapeY = 128;
var moneyShapeX = 270;
var moneyShapeY = 140;
var textboxShapeX = 330;
var textboxShapeY = 128;
var backgroundColor = 0;
var gameStart = false;
var badEnd = false;
var goodEnd = false;
var img1 = [];
var imageCount = 0;
var testLinks = ["https://i.imgur.com/VWoGtbO.jpg", 
             "https://i.imgur.com/OpLGpha.jpg",
             "https://i.imgur.com/1Ik4bPx.jpg",
             "https://i.imgur.com/vM6ZK9c.jpg",
             "https://i.imgur.com/8J6Gxdo.jpg",
             "https://i.imgur.com/yk3tV27.jpg",
             "https://i.imgur.com/FH9qhm4.jpg",
             "https://i.imgur.com/E7a5TDu.jpg",
             "https://i.imgur.com/9vRGrKE.jpg",
             "https://i.imgur.com/C4XhQaI.jpg",
             "https://i.imgur.com/NgIAvpS.jpg",
             "https://i.imgur.com/QRXsh9S.jpg",
             "https://i.imgur.com/04EkVKf.jpg",
             "https://i.imgur.com/0dOYwZv.jpg",
             "https://i.imgur.com/xc56D6n.jpg",
             "https://i.imgur.com/0sk94O3.jpg"];
var questionCount = 0;
let testQuestions = ["I can't code for life,", " but do you want to collaborate on this 15104 project?",
                  "Did you hear about the history exam tomorrow?", "I can’t believe it’s on EVERYTHING!",
                  "I heard Vivian got a 104/100", " on the recent physics test!",
                  "I really need to get some sleep,", "will you sign me in for lecture today?",
                  "There’s a frat party tonight,", "do you want to go and hang out?",
                  "OMG I heard there’s a new pho place downtown,", "are you interested??",
                  "There’s a library part time job on Handshake", "let’s apply together!",
                  "Let’s play","League of Legends tonight!",
                  "<Introduction to Javascript> is a required textbook,", "please get it by next class.",
                  "Re: Please see the HW attached,", "submit all to autolab by tonight at midnight.",
                  "I noticed that you have not paid attention in class.", "Is there something wrong?",
                  "Class, this project", "will be due in a week’s time.",
                  "Re: Would you like to be a generous supporter", "of the CMU community by becoming a donor?",
                  "The total amount of your food will be $15.76.", "Paid in card or cash?",
                  "New: Pittsburgh popcorn & smokey barbeque", "flavored mac and cheese",
                  "It’s 2am in the mornin’,","why are y’all still workin’?"]

var imageposX = 115;
var imageposY = 80;
var questionposY = 380;
var answerCount = 0;
let answerX = ["Um… Sure?",
               "What exam?",
               "Ha, I can do better",
               "Sure, go sleep",
               "Sure, I’ll go!",
               "YES LET’S GO",
               "Sure I’ll join",
               "I'll grab my laptop",
               "I’ll buy it",
               "Grinds through HW",
               "It won’t happen again",
               "Complete the task",
               "Fine I’ll donate",
               "Takes out debit card",
               "Gives it a try",
               "We have a deadline"];
let answerY = ["I prefer someone better",
               "Ya I studied all night",
               "She must’ve worked hard",
               "I’m also not going",
               "Nah, I’ll pass",
               "No I’m broke",
               "I’m too lazy",
               "My heart is in the work",
               "I’ll find a fake one",
               "Ignores this email",
               "Your class is boring",
               "Request for extension",
               "I’m not generous",
               "Gets something cheaper",
               "Gets something normal",
               "Cries hysterically"];
var answerposX = 90;
var answerposY = 430;
var timeTracker = 0;
var choices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var choices_A = [];
var academicsHP = 50;
var sanityHP = 50;
var financeHP = 50;
var socialHP = 50;
var HPposX = 35;
var HPposY = 40;
var logoPosX = 15;
var logoPosY = 30;
var subtract = true;
var monthCount = 0;
var star = [];
var cloud = [];
var crow = [];

function preload(){ //BY XU
    for (var i = 0; i < testLinks.length; i++){
        img1[i] = loadImage(testLinks[i]);
    }
}
function setup(){ //BY XIAOYU
    createCanvas(480,480);
    frameRate(10);
    //setup stars that will display at night
    for (var i = 0; i < 50; i ++) {
        var starX = random(width);
        var starY = random (0, height/2);
        star[i] = makeStar(starX, starY);
    }
    //setup clouds that will display at morning
    for (var i = 0; i < 10; i ++) {
        var cloudX = random(width);
        var cloudY = random (0, height/2);
        cloud[i] = makeCloud(cloudX, cloudY);
    }
    //setup crows that will display at afternoon
    for (var i = 0; i < 20; i ++) {
        var crowX = random(width);
        var crowY = random (0, height/2);
        crow[i] = makeCrow(crowX, crowY);
    }
}
function draw(){ //BY XU
    //starting page text
    background(0);
    fill("yellow");
    textSize(70);
    textFont('Courier');
    textAlign(CENTER);
    text('REIGNS', width/2, height/2);
    fill("white");
    textSize(20);
    text('- CMU EDITION -', width/2, height/2 + 50);
    textSize(15);
    text('Press Mouse To Start', width/2, height - 70); 
    //starting page logo
    fill("yellow");
    rectMode(CENTER);
    rect(width/2, 130, 250, 60);
    //academics logo
    noStroke();
    fill(0);
    beginShape();
    vertex(hatShapeX, hatShapeY);
    vertex(hatShapeX + 20, hatShapeY - 5);
    vertex(hatShapeX + 40, hatShapeY);
    vertex(hatShapeX + 20, hatShapeY + 5);
    vertex(hatShapeX, hatShapeY);
    endShape();
    rectMode(CORNER);
    rect(hatShapeX, hatShapeY, 1, 10);
    rect(hatShapeX + 10, hatShapeY, 20, 10);
    //sanity logo
    circle(heartShapeX, heartShapeY, 15);
    circle(heartShapeX + 10, heartShapeY, 15);
    triangle(heartShapeX - 8, heartShapeY, heartShapeX + 18, heartShapeY, heartShapeX + 6, heartShapeY + 15);
    //finance logo
    textSize(33);
    text('S', moneyShapeX, moneyShapeY);
    rect(moneyShapeX - 1.5, moneyShapeY - 22, 3, 25);
    //social life logo
    ellipse(textboxShapeX, textboxShapeY, 30, 20);
    triangle(textboxShapeX, textboxShapeY, textboxShapeX + 10, textboxShapeY, textboxShapeX + 10, textboxShapeY + 15);
    if(gameStart){ 
        backgroundChange();
        fill(backgroundColor);
        rectMode(CENTER);
        rect(width/2, height/2, 480, 480); 
        //display clouds when background is light gray
        if (timeTracker == 0) {
            displayCloud();
        }
        //display crows when background is dark gray
        if (timeTracker == 1) {
            displayCrow();
            addCrow();
            removeCrow();
        }
        //display stars when background is black
        if (timeTracker == 2) {
            displayStars();
        }        
        gameInterface();
    }
    //check if the game has ended
    checkStatus();
    //bad end
    if (badEnd){
        gameStart = false;
        background(0);
        fill("yellow");
        textSize(70);
        textFont('Courier');
        textAlign(CENTER);
        text('GAME OVER', width/2, height/2);
        fill("white");
        textSize(20);
        text('- SADLY YOU DIDNT GRADUATE -', width/2, height/2 + 50);
        textSize(15);
        text('Refresh Page to Start Over', width/2, height - 70); 
    }
    //goodEnd
    if (goodEnd){
        gameStart = false;
        background(0);
        fill("yellow");
        textSize(50);
        textFont('Courier');
        textAlign(CENTER);
        text('CONGRATULATIONS', width/2, height/2);
        fill("white");
        textSize(20);
        text('- YOU SUCCESFULLY GRADUATED CMU -', width/2, height/2 + 50);
        textSize(15);
        text('Refresh Page to Play Again', width/2, height - 70); 
    }
}
function mouseClicked(){ //BY XU
    gameStart = true;
}
function gameInterface(){ //BY XU
    //frame
    fill("yellow");
    rectMode(CENTER);
    rect(width/2, height/2 - 35, 280, 280);
    //implement images
    putImage();
    //implement question
    putQuestion();
    //implement answers
    putAnswers();
    putDate();
    hpTracker();

}
function putImage(){ //BY XIAOYU
    image(img1[imageCount], imageposX, imageposY);
}
function putQuestion(){ //BY XIAOYU
    fill("white");
    textFont('Courier');
    textAlign(CENTER);
    textSize(12.5);
    text(testQuestions[questionCount], width/2, questionposY);
    text(testQuestions[questionCount + 1], width/2, questionposY + 15);
}
function putAnswers(){ //BY XIAOYU
    //left side
    fill("yellow");
    textFont('Courier');
    textSize(12.5);
    text("A. " + answerX[answerCount], answerposX, answerposY);
    text("B. " + answerY[answerCount], answerposX + 280, answerposY);
}
function putDate(){ //BY XIAOYU
    fill("yellow");
    textFont('Courier');
    textAlign(CENTER);
    textSize(12.5);
    text(monthCount*2 + " months survived", width/2, 460);
}
function keyTyped(){ //BY XU
    if (key === 'a'){
        //time passes
        timeTracker ++;
        imageCount = floor(random(choices));
        questionCount = imageCount *2;
        answerCount = imageCount;
        subtractHP();
        monthCount ++;
    } else if (key === 'b'){
        //time passes
        timeTracker ++;
        imageCount = floor(random(choices));
        questionCount = imageCount *2;
        answerCount = imageCount;
        subtractHP();
        monthCount ++;
    }
    if (timeTracker >= 3){
        timeTracker = 0;
    }
}
function notRepeat(){ //BY XU
    while (choices_A.includes(imageCount)){
        imageCount = floor(random(choices));
    }
    if(choices_A.length < 6){
        choices_A.push(imageCount);
    }else {
        choices_A.shift();
        choices_A.push(imageCount);
    }
}
function hpTracker(){ //BY XIAOYU
    //academics logo
    noStroke();
    fill("yellow");
    beginShape();
    vertex(logoPosX, logoPosY);
    vertex(logoPosX + 20, logoPosY - 5);
    vertex(logoPosX + 40, logoPosY);
    vertex(logoPosX + 20, logoPosY + 5);
    vertex(logoPosX, logoPosY);
    endShape();
    rectMode(CORNER);
    rect(logoPosX, logoPosY, 1, 10);
    rect(logoPosX + 10, logoPosY, 20, 10);
    //academics hp
    fill("white");
    textFont('Courier');
    textAlign(CENTER);
    textSize(12.5);
    text(academicsHP + "/100", HPposX + 50, HPposY);
    //sanity logo
    fill("yellow");
    circle(logoPosX + 130, logoPosY, 15);
    circle(logoPosX + 130+ 10, logoPosY, 15);
    triangle(logoPosX + 130 - 8, logoPosY, logoPosX + 130 + 18, logoPosY, logoPosX + 130 + 6, logoPosY + 15);
    //sanity hp
    fill("white");
    text(sanityHP + "/100", HPposX + 130 + 30, HPposY);
    //finance logo
    fill("yellow");
    textSize(33);
    text('S', logoPosX + 250, logoPosY + 10);
    rect(logoPosX - 1.5 + 250, logoPosY + 10 - 22, 3, 25);
    //finance hp
    fill("white");
    textSize(12.5);
    text(financeHP + "/100", HPposX + 250 + 25, HPposY);
    //social life logo
    fill("yellow");
    ellipse(logoPosX + 370, logoPosY, 30, 20);
    triangle(logoPosX + 370, logoPosY, logoPosX + 370 + 10, logoPosY, logoPosX + 370 + 10, logoPosY + 15);
    //social hp
    fill("white");
    text(socialHP + "/100", HPposX + 400, HPposY);
}
function subtractHP(){ //BY XU
    //subtract hp
    if (imageCount <= 3){
        var randomNum = random(0, 1);
        if (randomNum < 0.5){
            academicsHP -= 10;
            sanityHP += 10;
        }else{
            academicsHP += 10;
            sanityHP -= 10;     
        }
    }
    if (imageCount >= 4 || imageCount <= 7){
        var randomNum = random(0, 1);
        if (randomNum < 0.5){
            financeHP -= 10;
            socialHP += 10;
        }else{
            financeHP += 10;
            socialHP -= 10;     
        }
    }
    if (imageCount >= 8 || imageCount <= 11){
        var randomNum = random(0, 1);
        if (randomNum < 0.5){
                academicsHP += 10;
            sanityHP -= 10;
        }else{
            academicsHP -= 10;
            sanityHP += 10;     
            }
    }
    if (imageCount >= 12 || imageCount <= 15){
        var randomNum = random(0, 1);
            if (randomNum < 0.5){
            financeHP += 10;
            socialHP -= 10;
        }else{
            financeHP -= 10;
            socialHP += 10;     
        }
    }
}
function checkStatus(){ //BY XU
    if (academicsHP == 100 || sanityHP == 100 || financeHP == 100 || socialHP == 100){
        badEnd = true;
    }
    if (academicsHP == 0 || sanityHP == 0 || financeHP == 0 || socialHP == 0){
        badEnd = true;
    }
    if (monthCount >= 24){
        goodEnd = true;
    }
}
function backgroundChange(){ //BY XIAOYU
    if (timeTracker == 0) {
        backgroundColor = 130;
    }
    if (timeTracker == 1) {
        backgroundColor = 95;
    }
    if (timeTracker == 2) {
        backgroundColor = 0;
    }
}
function drawStar(){ //BY XIAOYU
    noStroke();
    fill("yellow");
    push();
    translate(this.x, this.y);
    ellipse(20, 20, random(1,5), random(1,5));
    pop();
}
function makeStar(starX, starY){ //BY XIAOYU
    var makeStar = {x: starX,
                y: starY,
                draw: drawStar}
    return makeStar;
}
function displayStars(){ //BY XIAOYU
    for (i = 0; i < star.length; i++){
        star[i].draw();
    }
}
function drawCloud(){ //BY XU
    noStroke();
    fill(185);
    push();
    translate(this.x2, this.y2);
    ellipse(15, 26, 34, 20);
    ellipse(45, 30, 22, 25);
    ellipse(15, 35, 15, 16);
    ellipse(30, 28, 28, 26);
    pop();
}
function makeCloud(cloudX, cloudY){ //BY XU
    var makeCloud = {x2: cloudX,
                y2: cloudY,
                speed: -6,
                move: moveCloud,
                draw: drawCloud}
    return makeCloud;
}
function moveCloud(){ //BY XU
    this.x2 += this.speed;
    if(this.x2 <= -10){
        this.x2 += width;
    }
}
function displayCloud(){ //BY XU
    for (i = 0; i < cloud.length; i++){
        cloud[i].move();
        cloud[i].draw();
    }
}
function drawCrow(){ //BY XIAOYU
    strokeWeight(1);
    stroke(0);
    noFill();
    arc(this.x3, this.y3, this.size, this.size/2, PI, TWO_PI);
    arc(this.x3 + this.size, this.y3, this.size, this.size/2, PI, TWO_PI);
}
function makeCrow(crowX, crowY){ //BY XIAOYU
    var makeCrow = {x3: crowX,
                y3: crowY,
                speed2: random(3, 10),
                size: random(5, 10),
                move2: moveCrow,
                draw2: drawCrow}
    return makeCrow;
}
function moveCrow(){ //BY XIAOYU
    this.x3 -= this.speed2;
    this.y3 -= this.speed2 / random(5, 10);
}
function displayCrow(){ //BY XIAOYU
    for (i = 0; i < crow.length; i++){
        crow[i].move2();
        crow[i].draw2();
    }
}
function addCrow(){ //BY XU
    if (random(0,1) < 0.1) {
        var crowX = width;
        var crowY = random(0, height/2);
        crow.push(makeCrow(crowX, crowY));
    }
}
function removeCrow() { //BY XU
    var keep = [];
    for (i = 0; i < crow.length; i++) {
        if (crow[i].x3 + crow[i].size > 0) {
            keep.push(crow[i]);
        }
    }
    crow = keep;
}

For this final project, Xiaoyu and I collaborated to use p5js to create a CMU version of Reigns (a phone game). The game starts by pressing the mouse, then a series of questions will be presented, and the player uses ‘a’ key and ‘b’ key to make choices. There are four HP counters at the top of the screen, and they will fluctuate based on the choices the player makes. Once any of the four HPs reach 0/100 or 100/100, the game will present the bad end. If the player survives until 48 months (4 years), the game presents the good end.

We used things we learned in the past semester to give the game some particular features, such as the background changes, making sure the characters don’t repeat themselves, etc. We drew the characters ourselves in illustrator, and created the gamestart/end pages with p5js.

Caroline Song – Final Project

sketch

var color1; 
var color2;
var cSharp4;
var d4;
var dSharp4;
var e4;
var f4;
var fSharp4;
var g4;
var gSharp4;
var a5;
var aSharp5;
var b5;
var c5;
var cSharp5;
var d5;
var dSharp5;
var e5;

function preload() {
    //call loadSound() for all media files here
    cSharp4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/csharp.m4a");
    d4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/d.m4a");
    dSharp4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/dsharp.m4a");
    e4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/e-1.m4a");
    f4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/f.m4a");
    fSharp4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/fsharp.m4a");
    g4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/g.m4a");
    gSharp4 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/gsharp.m4a");
    a5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/a.m4a");
    aSharp5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/asharp.m4a");
    b5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/b.m4a");
    c5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/c.m4a");
    cSharp5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/csharp2.m4a");
    d5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/d2.m4a");
    dSharp5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/dsharp2.m4a");
    e5 = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/e2.m4a");
}

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

    //background color
    color1 = color(255, 248, 120);
    color2 = color(235, 101, 52);
    setGradient(color1, color2);

}

function draw() {
        //draw the piano
        drawPiano();

}

function setGradient(c1, c2) {
    //Creating red to yellow gradient
    for(var i = 0; i <= height/2; i++) {
      var x1 = map(i, 0, height/2, 0, 1);
      var c3 = lerpColor(color1, color2, x1);
      stroke(c3);
      line(0, i, width, i);
    }

}

function drawPiano() {
    //set stroke weight of piano
    stroke(0)
    strokeWeight(2);
    // draw white keys
    for (i = 0; i < width; i++) {
        fill(255);
        rect(0 + i * 70, 150, 70, 250);

    }
    // draw black keys
    for (i = 0; i < 2; i++) {
        fill(0);
        rect(-15 + 70 * i, 150, 30, 150);
        rect(475 + 70 * i, 150, 30, 150);
    }

    for(i = 0; i < 3; i++){
        fill(0);
        rect(195 + 70 * i, 150, 30, 150);
    }

}

function mousePressed() {
    //let each white key play a different whole note and display the note it's playing
    if (mouseX > 10 & mouseX < 60 && mouseY > 150 && mouseY < height) {
        d4.play();
        textSize(50);
        textAlign(CENTER);
        text('D4', width/2, height/3);
        fill(0);

    }

    if (mouseX > 80 & mouseX < 140 && mouseY > 150 && mouseY < height) {
        e4.play();
        textSize(50);
        textAlign(CENTER);
        text('E4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 140 & mouseX < 200 && mouseY > 150 && mouseY < height) {
        f4.play();
        textSize(50);
        textAlign(CENTER);
        text('F4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 220 & mouseX < 270 && mouseY > 150 && mouseY < height) {
        g4.play();
        textSize(50);
        textAlign(CENTER);
        text('G4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 290 & mouseX < 340 && mouseY > 150 && mouseY < height) {
        a5.play();
        textSize(50);
        textAlign(CENTER);
        text('A5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 360 & mouseX < 420 && mouseY > 150 && mouseY < height) {
        b5.play();
        textSize(50);
        textAlign(CENTER);
        text('B5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 420 & mouseX < 480 && mouseY > 150 && mouseY < height) {
        c5.play();
        textSize(50);
        textAlign(CENTER);
        text('C5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 500 & mouseX < 550 && mouseY > 150 && mouseY < height) {
        d5.play();
        textSize(50);
        textAlign(CENTER);
        text('D5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 570 & mouseX < width && mouseY > 150 && mouseY < height) {
        e5.play();
        textSize(50);
        textAlign(CENTER);
        text('E5', width/2, height/3);
        fill(0);
    }

    //let each black key play a different sharp/flat note and display the note it's playing
    if (mouseX > 0 & mouseX < 20 && mouseY > 150 && mouseY < 300) {
        cSharp4.play();
        textSize(50);
        textAlign(CENTER);
        text('C#4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 50 & mouseX < 90 && mouseY > 150 && mouseY < 300) {
        dSharp4.play();
        textSize(50);
        textAlign(CENTER);
        text('D#4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 190 & mouseX < 230 && mouseY > 150 && mouseY < 300) {
        fSharp4.play();
        textSize(50);
        textAlign(CENTER);
        text('F#4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 260 & mouseX < 300 && mouseY > 150 && mouseY < 300) {
        gSharp4.play();
        textSize(50);
        textAlign(CENTER);
        text('G#4', width/2, height/3);
        fill(0);
    }

    if (mouseX > 330 & mouseX < 370 && mouseY > 150 && mouseY < 300) {
        aSharp5.play();
        textSize(50);
        textAlign(CENTER);
        text('A#5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 480 & mouseX < 510 && mouseY > 150 && mouseY < 300) {
        cSharp5.play();
        textSize(50);
        textAlign(CENTER);
        text('C#5', width/2, height/3);
        fill(0);
    }

    if (mouseX > 540 & mouseX < 580 && mouseY > 150 && mouseY < 300) {
        dSharp5.play();        
        textSize(50);
        textAlign(CENTER);
        text('D#5', width/2, height/3);
        fill(0);
    }

}

function mouseReleased() {
    //if mouse is released, the text disappears
    color1 = color(255, 248, 120);
    color2 = color(235, 101, 52);
    setGradient(color1, color2);
}


For my final project, I created an interactive piano, with the intention of having children who are just starting to learn how to play the piano use this program as sort of a beginners trial. When pressing on a certain key, the name of that key lights up in the middle of the canvas, with the purpose of having users understand the name of the key while playing around with the piano and learning the actual names of the keys as well.

Ellan Suder – Final Project

I wanted to make something visually appealing and interesting to play around with. I first started with the white dot and kept building to it every few days, like the glowing colors, the grid background, and eventually some floating particles.

The spacebar control was actually a mistake I made when I was trying to put in the attraction behavior, but I ended up liking it so I added it to the final program.

Controls: Control the dot with your mouse. Press A to attract, hold dot to repel. Hold spacebar to stop and control particles with mouse. Press X to delete the text.

(Holding the dot while pressing A looks pretty cool!)

sketch

/*
Ellan Suder
15104 1 D
esuder@andrew.cmu.edu
Final Project
*/

// variables for main body
var t = 0;
var r = 0;
var xLoc = 250;
var yLoc = 250;
var diffx = 0;
var diffy = 0;
var targetX = 250;
var targetY = 250;
var diameter = 20;
var opacity = 0;
var dragging = false;

// variables for grid + dots
var freq = 0.001;
var dotColor = 35;

// variables for particles
var particles = [];
var numP = 30;
var particleColor = 255;
var capturedP = 0;
var particleCaptured = false;
var stop = false;
var attract = false;
var diffxP = 0;
var diffyP = 0;

// variable for showing text
var showText = true;
  
function setup() {
    createCanvas(500, 500);
    noCursor();
  
    // make particles
    for (var i = 0; i < numP; i++) {
        var p = makeParticle(random(width), random(height),
                             random(-0.1, 0.1), random(-0.1, 0.1));
        particles.push(p);
    }
}

// drawing the grid, 
// the main white dot, 
// the particles,
// and the instructions text.
function draw() {
    background(0,20);
    noStroke();
    
    // make grid pattern using for loop
    for(var q = 0; q < height/20; q++)
    {
      for(var w = 0; w < width/20; w++)
      {
           // I measured distance from each rect to the center
           // to create subtle gradient. smaller dist = lighter
           dGrid = dist(w*20,q*20,width/2,height/2);
           fill(30 - dGrid/10);
           rectMode(CENTER);
           rect(w*20+10,
                q*20+10,
                15,15);
        
           // creates dot if random number < freq
           // when mouse is pressed, freq increases and
           // chance of making dot increases
           e = random(0,1);
           if(e < freq) {
             fill(dotColor);
             ellipse(w*20+20,
                     q*20+20,
                     5,5);
           }
      }
    }
  
    diffx = mouseX - xLoc;
    diffy = mouseY - yLoc;
    r += 0.1;
    xLoc += 0.05*diffx + sin(r/20)/10;
    yLoc += 0.05*diffy + cos(r/20)/10;
  
    t += 0.01;
    randomColor = color(noise(t)*255,noise(t)*255,noise(t+60)*255, opacity);
    
    // main body (white dot controlled by mouseX and mouseY
    // with some easing for aesthetic purposes)
    fill(255);
    ellipse(xLoc, yLoc, diameter/2, diameter/2);
    // layers of colored circles
    opacity = 10;
    fill(randomColor);
    ellipse(xLoc + sin(r)/2, yLoc + cos(r)/2, diameter*2, diameter*2);
    ellipse(xLoc + sin(r)/2, yLoc + cos(r)/2, diameter*3, diameter*3);
    ellipse(xLoc + sin(r)/2, yLoc + cos(r)/2, diameter*5, diameter*5);
    ellipse(xLoc + sin(r)/2, yLoc + cos(r)/2, diameter*8, diameter*8);

    // when dragging == true, the main dot goes to the mouse
    // and spins faster
    if (dragging) {
        xLoc = mouseX + sin(r*50)*5;
        yLoc = mouseY + cos(r*50)*5;
    }
   
    // draw particles
    for (var i = 0; i < particles.length; i++) {
      var p = particles[i];
      p.step();
      p.draw();
    }
   
    if (showText) {
      let words = 'control the dot with your mouse.       press A to attract, hold dot to repel.  hold spacebar to stop and control particles with mouse.';
      textSize(28);
      strokeWeight(1);
      fill(255,100);
      text(words, width/2, height/2, 
                  width/2+30, height/2+80);
      textSize(15);
      text('press x to remove message.', 2*width/5, 3*height/4);
    }
}

// controlling the behavior of the particles
function particleStep() {
    if (stop) {
        // when space is pressed, particle motion halts
        // and you can control them with the mouse
        this.x += 0.05*diffx;
        this.y += 0.05*diffy;
        this.dx = 0;
        this.dy = 0;
    } else if (attract) {
        // when 'a' or 'A' is pressed, particles are drawn
        // to the mouse
        diffxP = mouseX - this.x;
        diffyP = mouseY - this.y;
        this.x += 0.05*diffxP;
        this.y += 0.05*diffyP;
    } else {
        // if no keys are pressed
        this.x += this.dx;
        this.y += this.dy + cos(r)/5;
    }
    
    // bounce off right
    if (this.x > width) {
        this.x = width - (this.x - width);
        this.dx = -this.dx;
    // bounce off left
    } else if (this.x < 0) {
        this.x = -this.x;
        this.dx = -this.dx;
    }
    // bounce off bottom
      if (this.y > height) {
        this.y = height - (this.y - height);
        this.dy = -this.dy;
    // bounce off top
    } else if (this.y < 0) {
        this.y = -this.y;
        this.dy = -this.dy;
    }
  
    // If mouse gets close to a particle, particle becomes captured
    // and the number of captured particles increases.
    // Size of orbit is fixed, but the modifier of the angle is
    // randomized so that each particle's orbit speed is different.
    if (dist(this.x, this.y, xLoc, yLoc) < 20) {
      this.particleCaptured = true;
      capturedP += 1;
      this.orbit += capturedP;
      this.modifier = random(-1,1);
    }
  
    // This controls what a captured particle does
    // captured particles orbit the mouse.
    // I keep track of number of captured particles
    // because each newly captured particle's orbit
    // increases slightly so they don't overlap.
    if (this.particleCaptured) {
      this.x = xLoc + this.orbit*sin(r*this.modifier);
      this.y = yLoc + this.orbit*cos(r*this.modifier);
    }
   
    // Captured particles get launched outwards when dragging == true
    // Reset orbit of all captured particles
    if (dragging & this.particleCaptured) {
      this.particleCaptured = false;
      this.orbit = 5;
      this.dx = random(-5,5);
      this.dy = random(-5,5);
      this.x += this.dx;
      this.y += this.dy;
    }
}

function particleDraw() {
    stroke(255,150);
    strokeWeight(3);
    point(this.x, this.y);
}

// when mouse is pressed close to the main white dot, 
// freq of grid dots increases, 
// dragging == true,
// and # of captured particles resets
function mousePressed() {
    if (dist(xLoc, yLoc, mouseX, mouseY) < 3*diameter) {
        dragging = true;
        capturedP = 0;
        freq = 0.006;
        dotColor = 60;
    }
}

function mouseReleased() {
    dragging = false;
    freq = 0.001;
    dotColor = 35;
} 

// when keys are pressed, 
// variables become true and the program changes the behavior
// in the particleStep function.
// spacebar -> stop particles and control them
// a or A -> particles attracted to mouse
function keyPressed() {
  if (key == ' ') {
      stop = true;
  }
  if (key == 'a' || key == 'A') {
      attract = true;
  }
  if (key == 'x' || key == 'X') {
      showText = false;
  }
}  

function keyReleased() {
  if (key == ' ') {
      stop = false;
  }
  
  if (key == 'a' || key == 'A') {
      attract = false;
  }
}

function makeParticle(px, py, pdx, pdy) {
    p = {x: px, y: py,
         dx: pdx, dy: pdy,
         particleCaptured: false,
         orbit: 5,
         modifier: 1,
         step: particleStep,
         draw: particleDraw
        }
    return p;
}

Ankitha Vasudev & Mari Kubota – Final Project


Instructions:

Up- w key

Down- s key

Left- a key

Right- d key

WARNING: DO NOT TOUCH THE FIRE

The objective of the game is to avoid the wild fires and reach the plant at the lower right hand corner of the screen. If you reach the plant, the words “You Win” appear along with the button that leads you to the next level. If you touch the fire, the words “You Lose” appear along with a restart button. The game has multiple levels which get harder as you go due to the increase in the number of fires and the heightened speed of the character. The level resets without an increase in difficulty if you touch the fire. The game is meant to bring awareness to forest fires caused by climate change.

Note: click on the screen to start the game 

sketch

// Ankitha Vasudev and Mari Kubota
// 15-104 Final Project

// ghost position
var dx = 0; 
var dy = 0;
var posX;
var posY;

//ghost speed
var speed = 1;

//sapling postion
var xsap = 375;
var ysap = 370;

//fire 
var shapes = [];

//level number
var lvl = 1;

var gameOn = true;
var lose = false;

function setup() {
	createCanvas(400, 400);
    //Makes fires and puts into array
	for (var i = 0; i < 15; i++) { 
        shapes.push(makeShapes());
    } 
}

function draw() { //written together 
	background(178, 204, 163);

	//calls functions
	sapling();
	ghost();
	pressingKey();
	levelNumber();
	
	for (i = 0; i < shapes.length; i++) { 
        shapes[i].display();

        //Game Over route
		if (posX >= shapes[i].x & posX <= shapes[i].x+30 
		    && posY >= shapes[i].y-25 && posY <= shapes[i].y+20) {
		 	lose = true;
		    speed = 0;
		    resetButton();
		    gameOn = false;
	    }
	}
 		
        //You Win route
    if (posX >= xsap-10 & posY >= ysap) { 
    	noStroke();
    	fill(0);
		textSize(50);
		// winsound.play();
		text('You Win!', 100, 200);
		speed = 0;
		nextLvl();
		gameOn = false;
    }

    if (lose==true){
    	noStroke();
		fill(0);
		textSize(50);
    	text('You Lose', 100, 200);
    }
}

function pressingKey() { //by Ankitha
    //Ghost movements controlled by keys

	if(keyIsDown(87)) { //W key
		dy -= speed;
	}	
    
	if(keyIsDown(83)) { //S key
		dy += speed;
	}	

	if(keyIsDown(65)){ //A key
		dx -= speed;
	}	

	if(keyIsDown(68)){ //D key
		dx+=speed;
	}
}

function ghost() { //by Mari
    //Ghost character shape and constraints
	noStroke();
	fill(255);
	posX = 25+dx;
	posY = 17+dy;

	if (posX <= 7){
		dx += speed;
	}

	if (posX >= width - 7){

		dx -= speed;
	}

	if (posY <= 9){
		dy += speed;
	}

	if (posY >= height-14){
		dy -= speed;
	}

	ellipse(25+dx,17+dy,17,20);//head
	ellipse(25+dx,27+dy,5,10);//feet
	ellipse(20+dx,27+dy,5,10);//feet
	ellipse(30+dx,27+dy,5,10);//feet
	fill(0);
	ellipse(20+dx,19+dy,3,3);//left eye
	ellipse(30+dx,19+dy,3,3);//right eye
	strokeWeight(1);
	stroke(0);
	line(22+dx,23+dy,28+dx,23+dy);
}

function shapesDisplay() { //by Ankitha
    //Make fire shape using vertex
    strokeWeight(3);
	stroke("red");
    fill("orange");
    beginShape();
    vertex(this.x-5, this.y);
    vertex(this.x, this.y+20);
    vertex(this.x+20, this.y+20);
    vertex(this.x+30, this.y+20);
    vertex(this.x+40, this.y+10);
    vertex(this.x+30, this.y-20);
    vertex(this.x+25, this.y+5);
    vertex(this.x+22, this.y-20);
    vertex(this.x+13, this.y);
    vertex(this.x+12, this.y-20);
    vertex(this.x-5, this.y);
    endShape();
}

function makeShapes() { //by Ankitha
    //randomizes fire position 
    var sh = {x: random(-30,430), 
    	      y: random(50,340),
              display: shapesDisplay}
    return sh;
}

function resetButton() { //by Mari
    //Reset button when game over appears
	stroke(0);
	strokeWeight(2);
	fill("red");
	rectMode(CORNER);
	rect(115,360,75,30);
	fill(0);
	textSize(12);
	noStroke();
	text("RESTART",128,379);
}

function nextLvl() { //by Mari
    //next level button when you win
	rectMode(CORNER);
	strokeWeight(2);
	stroke(0);
	fill("green");
	rect(30,360,75,30);
	fill(0);
	textSize(10);
	noStroke();
	text("Next Level",45,378);
}

function sapling() { //by Mari
    //sapling (the goal)
	fill("green");
	strokeWeight(5);
	stroke("green")
	line(xsap,ysap,xsap,ysap+20); //stem
	noStroke();
	ellipse(xsap-10,ysap,20,10); //left leaf
	ellipse(xsap+10,ysap,20,10); //right leaf
	fill("yellow");
	ellipse(xsap,ysap+20,10,10);
}

function levelNumber() { //by Mari
	noStroke();
	fill(0);
    textSize(15);
    text("Level: " + lvl, 340, 20);
}

function mouseClicked() { //by Ankitha
    //mouse clicking on button resets the games
    //game over button LOSE
	if (mouseX<245 & mouseX>130 && mouseY>360 && mouseY<400 && gameOn==false) { 
		shapes=[];
		gameOn=true;
		lvl = 1;
		speed=lvl;
		makeShapes();
		for (var i = 0; i < 15; i++) {
        	shapes.push(makeShapes());
    	} 
    	dx=0;
    	dy=0;
    	lose = false;
	}
    //next level button WIN
	if (mouseX<80 & mouseX>30 && mouseY>360 && mouseY<400 && gameOn==false) { 
		gameOn=true;
		lvl++;
		speed=lvl;
		makeShapes();
		for (var i = 0; i < 15; i++) {
        	shapes.push(makeShapes());
    	} 
    	dx=0;
    	dy=0;
	}
}

Steven Fei & Mike Jin – Final Project

Press your mouse to add planets and nebulas and use your mouse to hover around the Canvas and explore the universe!!

sketch

//Steven Fei & Fanjie Mike Jin
//Section A & C
//Final Project
//zfei@andrew.cmu.edu & fjin@andrew.cmu.edu
var starNumber = 150;//number of the stars on the background
var starsize = 1.5;//size of the stars
var sx = [];//array to define the x position of the stars
var sy = [];//array to define the y position of the stars
var sz = [];//array to define the z position of the stars
var amplitude = 3.14 * 3;//define the moving margin of the stars
var waveSpeed;//define the moving speed of the stars on the background
var theta = 0;//define the moving angle of the stars
var glowDefiner = [];//define the true false value for whether to let the star glow
var glowSize = 22;//glowing size of the stars
var newStars = [];//array for making new stars
var mouseXList = [];//arrays to store mouseX value
var mouseYList = [];//arrays to store mouseY value
var img; //load image for the earth texture mapping 
var w = 600 / 7 // devivded the canvas into seven regions and from left to right, the pitches of the piano sound will progressively become higher  
var newExplod = [];//array for making new explosion at the background
var mouseXListEx = [];//arrays to store mouseX value
var mouseYListEx = [];//arrays to store mouseY value


function setup() {
//load the background image for the texture mapping of the earth
//coded by Mike
    img = loadImage("https://i.imgur.com/lamlO83.jpg");
    createCanvas(600, 600,WEBGL);

//create values for the positions of the stars on the background
//coded by Mike
    for (var i = 0; i < starNumber; i++){
        sx.push(random(-width * 0.75, width * 0.75));
        sy.push(random(-height, height));
        sz.push(random(-width, height/2));
        var toggle = random(1.0);
        //define whether the stars on the background will glow
        if(toggle < 0.9){
            glowDefiner.push(false);
        }else{
            glowDefiner.push(true);
        }
    }
    for(var j = 0; j < glowDefiner.length; j++){
    print(glowDefiner[j]);
    }
}

function draw(){
    background(0);
    noStroke();
    normalMaterial();
    centerCube();//create a center star to give a sense of what perspective we are looking at
    makeCamera();//use the makeCamera function to change the viewport angle
    makeearth();
    push();
    //draw the stars on the background
    for(var i = 0; i < starNumber; i++){
        //coded by Mike
        push();
        waveSpeed = map(sz[i], -width, height/2, 15000, 60000);//define the moving speed of the stars
        theta += (TWO_PI / waveSpeed);//define the moving angle of the stars
        if(theta > amplitude){
            theta = -theta;//set the moving margins of the stars
        }
        sy[i] += sin(theta);//set the moving value to the positions
        sx[i] += cos(theta);//set the moving value to the positions
        translate(sx[i], sy[i], sz[i]);
        if(glowDefiner[i]){
            fill(255, 200, 130, 4);
            sphere(glowSize);//draw glow light of the sphere
        }
        fill("white");
        smooth();
        sphere(starsize);//draw the stars
        pop();
    }
    pop();
    //draw some new stars
    //coded by Steven
    if (mouseXList.length != 0){
        for(var k = 0; k < newStars.length; k++){
            newStars[k].updateStar();//animate the expansion of the stars
            push();
            translate(newStars[k].x, newStars[k].y,0);
            rotateX(frameCount * 0.05 + k*2);//rotate the new star
            rotateY(frameCount * 0.05 + k*2);//rotate the new star
            newStars[k].draw();//animate the emergence of the stars
            pop();
        } 
    }
    if(newStars.length > 4){
        newStars.shift();
    }

    push();
    //make the planet
    if (mouseXListEx.length != 0){
        for(var k = 0; k < newExplod.length; k++){
            newExplod[k].updateExplo();//animate the expansion of the stars
            push();
            translate(newExplod[k].x, newExplod[k].y,0);
            rotateX(frameCount * 0.05 + k*2);//rotate the new star
            rotateY(frameCount * 0.05 + k*2);//rotate the new star
            newExplod[k].draw();//animate the emergence of the stars
            pop();
        } 
    }
    if(newExplod.length > 2){
        newExplod.shift();
    }
    pop();

    
}

function makeCamera(){
//coded by Steven
    camX = map(mouseX, 0, width, -width/2, width/2);//changing camera position x
    camY = map(mouseY, 0, height, -height/2, height/2);//changing camera position y
    camZ = height/2;//changing camera position z
    camera(camX, camY, camZ,0,0,0,1,1,0);//allow the viewport angle to change
}
//make object to create new stars
function makeNewStar(x, y, radius){
//coded by Mike
    var newstar = {x: x,
                    y: y,
                    r: radius,
                    updateStar: updateStar,
                    draw: drawNewStar};
    return newstar;
}

function makeNewExplo(x, y, radius){
//coded by Mike
    var newExplo = {x: x,
                    y: y,
                    r: radius,
                    updateExplo: updateExplo,
                    draw: drawNewExplo};
    return newExplo;
}

//function to draw new star
function drawNewStar(){
//coded by Mike
    var color1 = random(150, 255);
    var color2 = random(100,180);
    var color3 = random(100,200);
    var density = random(14,20);//allow different numbers of the spheres to appear on the star
    for(var i = 0; i < density; i++){
        var lengthValue = map(i, 0, density, -PI, PI); //set longitudinal value
        for(var j = 0; j< density; j++){
            var widthValue = map(j, 0, density, -PI/2, PI/2);// set horizontal value
            var pX = this.r * sin(lengthValue) * cos(widthValue);
            var pY = this.r * sin(lengthValue) * sin(widthValue);
            var pZ = this.r * cos(lengthValue);
            push();
            fill(color1, color2, color3);
            translate(pX, pY, pZ);
            sphere(1.6);
            pop();
        }
    }
}

function drawNewExplo(){
//coded by Mike
    var color4 = random(100, 255);
    var color5 = random(100,180);
    var color6 = random(100,200);
    var density = random(12, 15);//allow different numbers of the spheres to appear for the explosion
    for(var i = 0; i < density; i++){
        var lengthValue = map(i, 0, density, -PI, PI); //set longitudinal value
        for(var j = 0; j< density; j++){
            var widthValue = map(j, 0, density, -PI/2, PI/2);// set horizontal value
            var pX1 = this.r * sin(lengthValue) * cos(widthValue * 0.5) * 0.5;
            var pY1 = this.r * sin(lengthValue * 0.5) * sin(widthValue) * 0.5;
            var pZ1 = this.r * cos(lengthValue);
            push();
            fill(color4, color5, color6);
            translate(pX1, pY1, pZ1);
            box(2, 2, 2);
            pop();
        }
    }
}

function updateStar(){
//coded by Mike
    this.r += random(0.5,2);//allow the new star to expand
}

function updateExplo(){
//coded by Mike
    this.r += random(1,2);//allow the new explosion to expand
}


function mousePressed(){
//coded by Steven
    var newStarMaking = [];
    var newMouseXList = [];
    var newMouseYList = [];
    var newExploMaking = [];
    var newmouseXListEx = [];
    var newmouseYListEx = [];
    var clickEx;//check whether there is existing new stars
    var click;//check whether there is existing new stars
    
    if(mouseXList.length == 0){
        click = 0;
        newStarMaking.push(newStars[0]);
        newMouseXList.push(mouseXList[0]);
        newMouseYList.push(mouseYList[0]);
    }
    else{
        for(var l = 0; l < newStars.length; l++){
            var distance = dist(mouseX - width/3, mouseY - height/3, newStars[l].x, newStars[l].y);
            if(distance <= 30){
                click = 1;
            }else{
                click = 0;
                newStarMaking.push(newStars[l]);
                newMouseXList.push(mouseXList[l]);
                newMouseYList.push(mouseYList[l]);
            }
        }
        newStars = newStarMaking;
        mouseXList = newMouseXList;
        mouseYList = newMouseYList;
    }
    if(click == 0){
        mouseXList.push(mouseX - width/3);
        mouseYList.push(mouseY - width/3);
        var newStar = makeNewStar(mouseX - width/3, mouseY-width/3, 30);
        newStars.push(newStar);
    }

    //add value to empty list
    if(mouseXListEx.length == 0){
        clickEx = 0;
        newExploMaking.push(newExplod[0]);
        newmouseXListEx.push(mouseXListEx[0]);
        newmouseYListEx.push(mouseYListEx[0]);
    }
    else{
    //assign initiating position according to the mouse postion
        for(var w = 0; w < newExplod.length; w++){
            var distance = dist(mouseX - width/3, mouseY - height/3, newExplod[w].x, newExplod[w].y);
            if(distance <= 30){
                clickEx = 1;
            }else{
                clickEx = 0;
                newExploMaking.push(newExplod[w]);
                newmouseXListEx.push(mouseXListEx[w]);
                newmouseYListEx.push(mouseYListEx[w]);
            }
        }
        //assign values back to the list
        newExplod = newExploMaking;
        mouseXListEx = newmouseXListEx;
        mouseYListEx = newmouseYListEx;
    }
    //avoid invalid value
    if(clickEx == 0){
        mouseXListEx.push(mouseX - width/3);
        mouseYListEx.push(mouseY - width/3);
        var newExplo = makeNewExplo(mouseX - width/3, mouseY-width/3, 300);
        newExplod.push(newExplo);
    }
}


//function to make a center planet to have some understanding of the perspective
//coded by Mike
function centerCube(){
    //make sure the location of the center planet is always at the center of the canvas
    push();
    var locX = mouseX - height / 2;
    var locY = mouseY - width / 2;
    ambientLight(50);
    directionalLight(255, 0, 0, 0.25, 0.25, 0);
    pointLight(0, 0, 255, locX, locY, 250);
    ambientMaterial(100);
    strokeWeight(0.5);
    stroke(255);
    smooth();
    sphere(40);
    pop();
    //first ring surronding the planet
    push();
    rotateZ(frameCount * 0.01);
    rotateX(frameCount * 0.01);
    rotateY(frameCount * 0.01);
    strokeWeight(0.5);
    smooth();
    stroke(255);
    torus(60, 0.5);
    pop();
    //second ring surronding the planet
    push();
    rotateZ((100+ frameCount) * 0.01);
    rotateX((100 + frameCount) * 0.01);
    rotateY((100+ frameCount) * 0.01);
    smooth();
    strokeWeight(0.5);
    stroke(255);
    torus(70, 0.5);
    pop();
    //third ring surronding the planet
    push();
    rotateZ((200+ frameCount) * 0.01);
    rotateX((200 + frameCount) * 0.01);
    rotateY((200+ frameCount) * 0.01);
    smooth();
    strokeWeight(0.5);
    stroke(255);
    torus(80, 0.5);
    pop();
    //fourth ring surronding the planet
    push();
    rotateZ((300+ frameCount) * 0.01);
    rotateX((300 + frameCount) * 0.01);
    rotateY((300+ frameCount) * 0.01);
    smooth();
    strokeWeight(0.5);
    stroke(255);
    torus(90, 1);
    pop();
}
//function to make a earth adjacent to the center planet 
//coded by Mike
function makeearth(){
    push();
    translate(width / 2, height / 3, -150);
    rotateX(frameCount * 0.05);
    rotateY(frameCount * 0.05);
    texture(img);
    sphere(20);
    pop();
}

 

In this project, we aim to establish an interactive universe made possible by using the P5 3D geometry and 3D lighting. When you are hovering around in this universe, the stars and planets will move according to your mouse position. When you lower the mouse position, the screen will be zoomed out and when you higher the mouse, the screen will zoom in more.  When the mouse is pressed, new “stars” which look like the colorful spheres composed of smaller spheres with galaxy-like explosion will happen randomly on the screen and would expand further until they can be seen no more. However, once you click on the screen, you will be able to see them again. The small spheres are glowing on the background to have an interstellar appearance. The center spindle-like sphere and an “Earth” like sphere are created to give us a general understanding of what perspective we are looking at the canvas.