Anthony Ra – Final Project

The premise of this game is to prevent a crazy, out-of-control lion from getting a head injury and a concussion. Using the character, Ryan, from the messaging app, Kakao Talk, use the spacebar key to control Ryan in the y-axis and have him avoid the sharp sticks. Continuous head injuries can lead to concussions, brain damage, loss of memory and other medical disorders.

Ryan just ate 50 bags of Gushers and is very jittery. It is your job to prevent him from running into those sticks. Enjoy!!

sketch

/* Anthony Ra
Section-A
ahra@andrew.cmu.edu
Final Project */

var player;
var obstacles = [];
var score = 0;
var terrainSpeed = 0.00025;
var terrainDetail = 0.006;
var gameOverFrame = 0;
var gameOver = false;

function setup() {
    createCanvas(350, 600);
    player = new Player();
    obstacles.push(new Obstacle());

    reset();
}

function draw() {
  background(225, 175, 0);
  /* background landscape moving*/
  noStroke();
  fill(175, 145, 0);
  beginShape();
  vertex(0, height);
  for (var i = 0; i < width; i++) {
    var t = (i * terrainDetail) + (millis() * terrainSpeed);
    var y = map(noise(t), 0, 1, height/12, height/2);
    vertex(i, y);
  }
  vertex(width, height);
  endShape();
  /* obstacles moving from right to left */
  for (var i = obstacles.length - 1; i >= 0; i--) {
    obstacles[i].show();
    obstacles[i].update();
    /* when obstacle hits player */
    if (obstacles[i].hits(player)) {
      gameEnds();
    }
    /* when obstacle leaves the screen */
    if (obstacles[i].offscreen()) {
      obstacles.splice(i, 1);
    }
  }
  player.update();
  player.show();
  /* continuously having the obstacles appear */
  if (frameCount % 30 == 0) {
    obstacles.push(new Obstacle());
  }
  /* when player passes each obstacle */
  if (frameCount % 45 == 0) {
    score++;
  }

  showScore();
}

/* game controls for player */
function keyPressed() {
  if (key === ' ') {
    player.up();
    if (gameOver) {
      reset();
    }
  }
}

function Player() {
  this.y = height/2;
  this.x = 50;
/* applying earth factors to player */
  this.gravity = 0.5;
  this.lift = -10;
  this.velocity = 0;
/* shows player on the left side of the screen */
  this.show = function() {
    stroke(0);
    strokeWeight(1);
    fill(204, 102, 0);
    ellipse(this.x - 10, this.y - 15, 10, 10);
    ellipse(this.x + 10, this.y - 15, 10, 10);
    ellipse(this.x, this.y, 40, 37);
    /* eyebrows and eyes */
    stroke(0);
    strokeWeight(1);
    line(this.x - 5, this.y - 5, this.x - 10, this.y - 5);
    line(this.x + 5, this.y - 5, this.x + 10, this.y - 5);
    fill(0);
    ellipse(this.x - 7.5, this.y, 2, 2);
    ellipse(this.x + 7.5, this.y, 2, 2);
    /* snout and nose */
    noStroke();
    fill(255);
    ellipse(this.x - 3, this.y + 7, 7, 5);
    ellipse(this.x + 3, this.y + 7, 7, 5);
    fill(0);
    ellipse(this.x, this.y + 5, 3, 3);
  }
/* allows player to move in y axis with gravity still in effect */
  this.up = function() {
    this.velocity += this.lift;
    this.velocity += 0.7;
  }
/* applying gravity on player */
  this.update = function() {
    this.velocity += this.gravity;
    this.y += this.velocity;
/* if player touches the bottom of the screen */
    if (this.y > height) {
      this.y = height;
      this.velocity = 0;
    }
/* if player touches top of the screen */
    if (this.y < 0) {
      this.y = 0;
      this.velocity = 0;
    }
  }
}

function Obstacle() {
  this.top = random(height * 1/2);
  this.bottom = random(height * 1/3);
  this.x = width;
  this.w = 35;
  this.speed = 3;

  this.highlight = false;
/* when player makes contact with an obstacle */
  this.hits = function(player) {
    if (player.y < this.top || player.y > height - this.bottom) {
      if (player.x > this.x & player.x < this.x + this.w) {
        this.highlight = true;
        return true;
      }
    }
    return false;
  }
/* shows the obstacle coming from the right of the screen */
  this.show = function() {
    fill(87, 60, 0);
    rect(this.x, 0, this.w, this.top);
    rect(this.x, height - this.bottom, this.w, this.bottom);
    triangle(this.x, this.top, this.x + this.w, this.top,
      this.x + (this.w/2), this.top + 50);
    triangle(this.x, height - this.bottom, this.x + this.w, height - this.bottom,
      this.x + (this.w/2), height - this.bottom - 50);
  }

  this.update = function() {
    this.x -= this.speed;
  }
/* when obstacles go offscreen */
  this.offscreen = function() {
    if (this.x < -this.w) {
      return true;
    } else {
      return false;
    }
  }
}
/* text on the upper hand side */
function showScore() {
  textSize(15);
  fill(255);
  textAlign(CENTER);
  text("SCORE: " + score, width - 50, 30);
  text("KAKAO RUN", 50, 30);
}
/* game over */
function gameEnds() {
  textSize(50);
  textAlign(CENTER);
  fill(255);
  textFont('Arial');
  text("GAME OVER", width/2, height/2);
  gameOver = true;
  noLoop();
}
/* resetting the game from start */
function reset() {
  gameOver = false;
  score = 0;
  obstacles = [];
  player = new Player();
  obstacles.push(new Obstacle());
  gameOverFrame = frameCount - 1;
  loop();
}

Audrey Zheng – Final Project

sketch

//Audrey Zheng
//Section A
//audreyz@andrew.cmu.edu




var cubex = 10;
var cubey = 20;
var cubeWidth = 20;

var cube;
var cube2;


var cx;
var cy;

var systems;


function setup() {
    createCanvas(300, 300);
    background(220);
   


    // osc = new p5.TriOsc();
    // osc.freq(880.0);
    // osc.amp(0.1);
    // osc.start();


    cx = width/2;
    cy = width/2;

    cube1 = new cube(200,30);
    cube2 = new cube(20,20);
    cube3 = new cube(150,150);

    
    systems = [];
    

}

function draw() {
    if (millis() > 2000) {
        //osc.stop();
        //noLoop();
    }

    //rect(cubex, cubey, cubeWidth, cubeWidth);

    cube1.display();
    cube2.display();
    cube3.display();

    for (i = 0; i <systems.length; i ++) {
        systems[i].display();
    }
    
    if (systems.length==0) {
        textAlign(CENTER);
        text("Click to add cubes", width/2, height/2);
    }

}

function cube(x,y) { //the cube
    this.x = x;
    this.y = y;

    this.width = 20;


    this.NW =[this.x, this.y];    
    this.NE = [x+this.width, this.y];

    this.SE = [this.x+this.width, y+this.width];

    this.SW = [this.x, y+this.width];

    this.larger = new square(x,y,this.width, this.width);
    this.smaller = new square(x + (cx -x) * 0.25, y + (cy - y) *0.25, this.width * 0.75, this.width * 0.75);


    this.NWs =[(this.x + (cx - this.x) * 0.20), this.y + (cy - this.y) * 0.20];
     
    this.NEs = [(this.x + (cx - this.x) * 0.20) + (this.width * 0.8), this.y + (cy - this.y) * 0.20];

    this.SEs = [(this.x + (cx - this.x) * 0.20) + (this.width * 0.8), this.y + (cy - this.y) * 0.20 + (this.width * 0.8)];

    this.SWs = [(this.x + (cx - this.x) * 0.20), this.y + (cy - this.y) * 0.20 +(this.width * 0.8)];




   
    this.display = function() {
        rect(this.x, this.y, this.width, this.width);
        rect(this.x + (cx - this.x) * 0.20, this.y + (cy - this.y) * 0.20, this.width * 0.8, this.width * 0.8);
        line(this.NW[0], this.NW[1], this.NWs[0], this.NWs[1]);
        line(this.NE[0], this.NE[1], this.NEs[0], this.NEs[1]);
        line(this.SE[0], this.SE[1], this.SEs[0], this.SEs[1]);

        line(this.SW[0], this.SW[1], this.SWs[0], this.SWs[1]);



    };

}

function square(x,y,w,h) {
    this.x = x;
    this.y = y;
    this.width = w;
    this.height = h;

    this.getCorners = function() {
        var NW =[x-w/2,y-h/2];
        //print(NW);
        var NE = [x+w/2, y-h/2];
        var SE = [x+w/2, y-h/2];
        var SW = [x-w/2, y+h/2];

        return [NW,NE,SE,SW];
    };
}


function mousePressed() {
    this.p = new cube(mouseX,mouseY);
    systems.push(p);
    print(systems);
}




function fillFront() {

}

function fillBottom() {

}

function fillTop() {

}

function fillLeft() {

}

function fillRight() {

}


Sophie Chen – Final Project

My final project uses the webcam to generate simple animations that will follow motion/gestures of the user through a red color marker. For the best experience, make sure to only have one red object in front of the camera at a time.

Instructions:

  1. grab something red (any relatively small red object would work best, or just pull up a red image on your phone)

  2. hold it within range of the webcam, with the red facing the camera

  3. wave/draw/play

    *to see the animations alone, you can turn the camera image on/off by pressing camera button

    press on shape 1, shape 2, and shape 3 to see different shapes

    works best in a brightly lit room, so the computer can recognize the red object

sketch

// Sophie Chen
// sophiec@andrew.cmu.edu
// 15-104 Final Project
// Dec 2018

// This program uses the webcam and generates a simple animation that will
// follow a red color marker. For best user experience, make sure to only have
// one red object in front of the camera at a time.

// declare variables
var myCaptureDevice;
var xarray = []; // array to store the value of x positions
var yarray = []; // array to store the value of y positions
var limitSize = 50; // length limit of x and y arrays
var cameraOn = 1; // camera switch - default on
var shapeOne = 1; // default starts with shape one
var shapeTwo = -1; // shape two starts false
var shapeThree = -1; // shape three starts false
var turtle; // define turtle graphics variable


// setup loads the webcam input and initializes turtle graphics
function setup() {
    createCanvas(600, 430);
    myCaptureDevice = createCapture(VIDEO);
    myCaptureDevice.size(600, 430);
    myCaptureDevice.hide();
    turtle = makeTurtle(0, 0);
    turtle.penDown();
    turtle.setColor(255);
}

// this function tests for color as a condition
function isColor(c) {
	return (c instanceof Array);
}

// this function draws the animations on top of the camera image
function draw() {
    myCaptureDevice.loadPixels();
    // if cameraOn is true, load camera output
    // if cameraOn is false, camera output is not visible, load black background
    if (cameraOn === 1){
        image(myCaptureDevice, 0, 0);
    } else {
        background(0);
    }

    //call functions that draw the buttons
    drawCamButton();
    drawShapeButton();
    drawShapeTwoButton();
    drawShapeThreeButton();

    //declare variables used to calculate centerpoint of red object/marker
    var xMin = 0; // x value minimum 
    var xMax = 600; // x value maximum
    var yMin = 0; // y value minimum
    var yMax = 430; // y value maximum

    // for loop that draws the shape animations
    for (var a = 0; a < xarray.length; a++){ 
        // declare color and size variables based on forloop
        var size = (50 / xarray.length) * a;
        var r = map(a, 0, xarray.length, 0, 255);
        var g = map(a, 0, xarray.length, 0, 255);
        var b = map(a, 0, xarray.length, 0, 255);

        // Shape 1: filled ellipse
        if (shapeOne === 1){
            shapeTwo = -1;
            shapeThree = -1;
            noStroke();
            fill(r, g, 255);
            ellipse(xarray[a], yarray[a], size, size);
        }


        // Shape 2: outlined ellipse
        if (shapeTwo === 1) {
            shapeOne = -1;
            shapeThree = -1;
            noFill();
            stroke(r, g, b);
            strokeWeight(1);
            ellipse(xarray[a], yarray[a], size, size);
        }

        
        // Shape 3: turtle graphics
        if (shapeThree === 1) {
            shapeOne = -1;
            shapeTwo = -1;
            turtle.setColor(color(205, 255, 10));
            turtle.goto(xarray[a], yarray[a]);
            turtle.forward(25);
            turtle.right(90);  
        }
    }

    // get the color value of every 5 pixels of webcam output
    for (var i = 0; i < width; i += 5){
        for (var j = 0; j < height; j+= 5) {
            var currentColor = myCaptureDevice.get(i, j);
            // targetColor: color(255, 0, 0);

            // calculate the difference between current color and target color
            var dr = red(currentColor) - 255;
            var dg = green(currentColor) - 0;
            var db =  blue(currentColor) - 0;
            
            // if current color is close enough to target color (~120), calculate
            // center point of the red area
            if (isColor(currentColor)){
               var dist = sqrt(sq(dr) + sq(dg) + sq(db));
               if (dist < 120) {
                    // find center point of red marker
                    if (i > xMin){ 
                        xMin = i;
                    }
                    if (i < xMax){
                        xMax = i;
                    }

                    if (j > yMin){
                        yMin = j;
                    }
                    if (j < yMax){
                        yMax = j;
                    } 
                }   
    		}
    	}
    }

    // push the newly discovered x, y into the array 
    xarray.push((xMin + xMax) / 2);
    yarray.push((yMin + yMax) / 2); 
    
    // if array is full, pop something out from the beginning
    while (xarray.length > limitSize) {
        xarray.shift();
        yarray.shift();
    }
}

// functions to trigger responses of buttons pressed
function mouseClicked(){
    // if camera button is pressed, toggle on/off
    if (mouseX > 10 & mouseX < 60 && mouseY > 10 && mouseY < 30){
        cameraOn = -cameraOn;
    }
    // if shape 1 button is pressed, show shape 1, disable shape 2 & 3
    if (mouseX > 10 && mouseX < 60 && mouseY > 20 && mouseY < 60){
        shapeOne = 1;
        shapeTwo = -1;
        shapeThree = -1;
    }
    // if shape 2 button is pressed, show shape 2, disable shape 1 & 3
    if (mouseX > 10 && mouseX < 60 && mouseY > 60 && mouseY < 90){
        shapeTwo = 1;
        shapeOne = -1;
        shapeThree = -1;
    }
    // if shape 3 button is pressed, show shape 3, disable shape 1 & 2
    if (mouseX > 10 && mouseX < 60 && mouseY > 90 && mouseY < 120){
        shapeThree = 1;
        shapeTwo = -1;
        shapeOne = -1;
    }

}

// camera button
function drawCamButton(){
    fill(255);
    stroke(0);
    rect(10, 10, 50, 20);
    noStroke();
    fill(0);
    text('camera', 15, 23);
}

// shape 1 button
function drawShapeButton(){
    fill(255);
    stroke(0);
    rect(10, 40, 50, 20);
    noStroke();
    fill(0);
    text('shape 1', 15, 54);
}

// shape 2 button
function drawShapeTwoButton(){
    fill(255);
    stroke(0);
    rect(10, 70, 50, 20);
    noStroke();
    fill(0);
    text('shape 2', 15, 85);
}

// shape 3 button
function drawShapeThreeButton(){
    fill(255);
    stroke(0);
    rect(10, 100, 50, 20);
    noStroke();
    fill(0);
    text('shape 3', 15, 116);
}

//////////////////////////////////////////////////////////////////////////////
function turtleLeft(d){this.angle-=d;}function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;this.goto(newx,newy);}function turtleBack(p){
this.forward(-p);}function turtlePenDown(){this.penIsDown=true;}
function turtlePenUp(){this.penIsDown = false;}function turtleGoTo(x,y){
if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);
line(this.x,this.y,x,y);}this.x = x;this.y = y;}function turtleDistTo(x,y){
return sqrt(sq(this.x-x)+sq(this.y-y));}function turtleAngleTo(x,y){
var absAngle=degrees(atan2(y-this.y,x-this.x));
var angle=((absAngle-this.angle)+360)%360.0;return angle;}
function turtleTurnToward(x,y,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}function turtleFace(angle){
this.angle = angle;}function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:color(128),weight:1,left:turtleLeft,
right:turtleRight,forward:turtleForward, back:turtleBack,penDown:turtlePenDown,
penUp:turtlePenUp,goto:turtleGoTo, angleto:turtleAngleTo,
turnToward:turtleTurnToward,distanceTo:turtleDistTo, angleTo:turtleAngleTo,
setColor:turtleSetColor, setWeight:turtleSetWeight,face:turtleFace};
return turtle;}

I really enjoyed the camera interaction aspect of the text rain assignment, which is why I wanted to work more with live cam for this project and create something where the user has even more direct control. Overall this project was a lot more challenging than I expected, but that also made it more rewarding when I finally got it to work. I’m glad I went with color recognition for the marker because it allows for precise control and is more forgiving towards the user in terms of what environment they should be in when using this program. The most time-consuming and unexpected challenge was the lagging and freezing that comes with working with so many pixels, so trying to figure out what was causing the freezing took a lot longer than changing the code to fix it. Since the animations are on the simple side, I decided to include 3 different options. Ideally the animations would’ve been more complex, that’s something I hope to keep working on in the future. Below are screenshots from me using the program to give an idea of how it would look like when it’s working.

shape 3 with camera input on, drawn with a red pen as color marker
shape 1 with camera output hidden
shape 2 with camera output hidden

 

 

Joanne Lee – Term Project

Term Project

// Joanne Lee
// Section C
// joannele@andrew.cmu.edu
// Term Project

// Visual Quadrant Map:
// Q1  Q2  Q3
// Q4  Q5  Q6
// Q7  Q8  Q9

// logistics
var game = "inactive"
var fCount = 150;
var playBoardW = 270;

// playing board variables
var boardWeight = 10;
var playBoxW = 270;
var effectCounter = 6;

// white, orange, gray box variables
var boxW = playBoardW / 4;
var boxX = [165.625, 250, 334.375];
var boxY = [240.625, 325, 409.375];
var grayBoxes = [];
var newOrange = false;
var whiteX = 0;
var whiteY = 2;
var orangeX = 2;
var orangeY = 0;

// score keeper
var score = 0;
var bestScore = 0;

// sound variables
var coin;
var boing;

function preload() {
    coin = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/coin.wav");
    coin.setVolume(0.5);
    boing = loadSound("https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/boing.wav");
    boing.setVolume(0.5);
}

function setup() {
    createCanvas(500,650);
    frameRate(100);
}

function draw() {
    background(255,211,222);

    // "growth" effect seen when white + gray boxes collide
    if (effectCounter < 2) { // staggered growth effect
        playBoxW = 280;
    }
    if (effectCounter > 2 & effectCounter < 4) { // staggered growth effect
        playBoxW = 290;
    }
    if (effectCounter > 4 & effectCounter < 6) { // staggered growth effect
        playBoxW = 280;
    }
    if (effectCounter > 6) { // staggered growth effect
        playBoxW = 270;
    }
    effectCounter += 1;

    drawPlayingBoard();
    drawPlayerBox();
    drawGoalBox();
    displayScore();

    if (game == "inactive") {
        displayStarterText();
    }
    if (game == "active") {
        drawGrayBox();
        // control speed that new boxes are generated
        if (frameCount % fCount == 0 & frameCount != 0) {
            generateGrayBox();
        }
        updateGrayBox();
        checkCollision();
    }
}

function displayScore() {
    fill(255,80); // display current score
    textSize(200);
    textStyle(BOLD);
    textFont('Helvetica');
    if (score < 10) {
        text(score, width - 120, height - 10);
    }
    else if (score < 100) { // shift over one spot for 2 digit score
        text(score, width - 225, height - 10);
    }
    else if (score < 999) {
        text(score, width - 330, height - 10 );
    }
    if (score >= bestScore) { // record the best score
        bestScore = score
    }

    fill(255); // display the best score
    textSize(20);
    textStyle(BOLD);
    textFont('Helvetica');
    text("High Score  " + bestScore, 110, height-160);
}

function displayStarterText() {
    fill(40,99);
    textSize(20);
    textStyle(BOLD);
    textFont('Helvetica');
    text("Press enter to begin", 155, height/2);
}

function drawPlayingBoard() { // light pink w/ thick white border
    fill(255,211,222);
    stroke(255); 
    strokeWeight(boardWeight);
    rectMode(CENTER);
    rect(width / 2, height / 2, playBoxW, playBoxW);
}

function drawPlayerBox() { // white box, starts in Q7
    strokeWeight(0);
    fill(255);
    rect(boxX[whiteX], boxY[whiteY], boxW, boxW);
}

function drawGoalBox() { // orange box, starts in Q3
    fill(255,170,107);
    rect(boxX[orangeX], boxY[orangeY], boxW*0.7, boxW*0.7);
}

function randomOrangeXY() { // generate random position for orange box
    var randX = int(random(0,3));
    var randY = int(random(0,3));

    // make sure orange x & y are in same line or column as previous position
    while (randX == whiteX || randY == whiteY) {
        randX = int(random(0,3));
        randY = int(random(0,3));
    }
    orangeX = randX;
    orangeY = randY;
}

function checkBoard() {
    // if white box position = orange box, you need a new orange box
    if (whiteX == orangeX & whiteY == orangeY) {
        coin.play();
        newOrange = true; // indicate need for new orange box
        score += 1; // increment score

        // increase speed at which new boxes spawn, cap at 90 frame count
        if (score % 10 == 0 & score != 0 && fCount > 90) {
            fCount -= 20;
        }   
    }

    // if board needs new orange box, randomly generate
    if (newOrange == true) {
        randomOrangeXY();
        newOrange = false;
    }
}

function generateGrayBox() { // will create a box with random attributes
    if (int(random(0,2)) == 0) { // create a box going left or right
        if (int(random(0,2)) == 0) { // create box going right
            createBox(-23.625, boxY[int(random(0,3))], 1, 0);
        }
        else { // create box going left
            createBox(523.625, boxY[int(random(0,3))], -1, 0);
        }
    }
    else { // create a box going up or down
        if (int(random(0,2)) == 0) { // create box going down
            createBox(boxX[int(random(0,3))], -23.625, 0, 1);
        }
        else { // create box going up
            createBox(boxX[int(random(0,3))], 673.625, 0, -1);
        }
    }
}

function createBox(tx, ty, dx, dy) { // store as an object in the array
    var grayBox =   { x: tx, y: ty,
                      dx: dx, dy: dy,
                      speed: 2.5, state: 'active'
                    }
    grayBoxes.push(grayBox);
}

function updateGrayBox() { // moves the box along
    for (var a = 0; a < grayBoxes.length; a ++) {
        grayBoxes[a].x += grayBoxes[a].dx * grayBoxes[a].speed;
        grayBoxes[a].y += grayBoxes[a].dy * grayBoxes[a].speed;
    }
}

function drawGrayBox() {
    for (var b = 0; b < grayBoxes.length; b ++) {
        fill(107,105,107);
        rect(grayBoxes[b].x, grayBoxes[b].y, boxW*0.7, boxW*0.7);
    }
}

function checkGrayBox() {
    for (var c = 0; c < grayBoxes.length; c ++) {
        // delete box from array once it is off the screen
        if (grayBoxes[c].x < -24 || (grayBoxes[c].x > 524) || 
            (grayBoxes[c].y < -24) || (grayBoxes[c].y > 674)) {
            count += 1;
            grayBoxes.splice(c,1);
        }
    }
}

function checkCollision() {
    for (var d = 0; d < grayBoxes.length; d ++) {
        if ((grayBoxes[d].x + boxW * 0.35) > (boxX[whiteX] - boxW * 0.5) &
            (grayBoxes[d].x - boxW * 0.35) < (boxX[whiteX] + boxW * 0.5) &&
            (grayBoxes[d].y - boxW * 0.35) < (boxY[whiteY] + boxW * 0.5) &&
            (grayBoxes[d].y + boxW * 0.35) > (boxY[whiteY] - boxW * 0.5)) {
            gameReset();
            break;
        }
    }
}

function gameReset() {
    boing.play();
    score = 0;
    grayBoxes = [];
    fCount = 150;
    effectCounter = 0;
    game = "inactive";
}

function keyPressed() {
    if (game == "active") {
        if (keyCode == UP_ARROW & whiteY > 0) {
            whiteY -= 1;
        }
        if (keyCode == DOWN_ARROW & whiteY < 2) {
            whiteY += 1;
        }
        if (keyCode == LEFT_ARROW & whiteX > 0) {
            whiteX -= 1;
        }
        if (keyCode == RIGHT_ARROW & whiteX < 2) {
            whiteX += 1;
        }
    }
    if (game == "inactive" & keyCode == ENTER) {
        game = "active"
        generateGrayBox();
    }

    // CHECK BOARD: to see if white box "ate" orange box
    checkBoard();
}

The objective of the game is quite simple: collect the orange box by using your arrow keys to move the white box while avoiding the incoming gray boxes!

As the game progresses, you’ll find that the gray boxes will appear quicker, creating more obstacles to dodge. The game was based off of a game I saw a while ago, but was unable to find again on the internet — so the idea is not original, however, the interface is!

Although seemingly simple, there were a lot of technical obstacles I had to overcome with the main one being having to make sure that too many gray boxes did not appear at once. I ran into some bugs along the way, but I believe that my current code is clean and efficient!

Something I also tried to focus on was simple, but meaningful UI. Attention to detail was put in to small things such as a visual (and audio) cue when you mess up or the placement of the score. Hopefully this is a soothing yet addictive game that will get people through finals week! It was fun to create something of my own.

cmhoward-finalproject

For my project, I created an animated children’s book. This project was really exciting to create as I was able to practice using simple and more complex animation. With having 10 pages, I focused on experimenting with different kinds of animations and page turning effects. All of the backgrounds were drawn by me! The animated objects were also drawn by me, or created in p5.js. For the sake of cleanliness and consistency, I decided that drawing the background images myself would be the best possible solution.

The code is structured by creating an array of functions that implements the functions by indexing through a page number counter.

Detailed page explanations below:

On page 4, the Giraffe suggests for the Lion to sleep with a spoon under his pillow to make it rain, so the user must move the spoon to the pillow. When the spoon is within the boundaries of the pillow, it flips to the next page. 

On page 5, I chose to do a simple page turning animation where the user must click within the boundary of the page turning image. While not nearly as complex as other pages, it was necessary to add this page for the sake of the story!

On page 9, the animals are having a party so I created an object animation of balloons floating to the top of the page. When the array length (i.e # of balloons) reaches 10 balloons, it moves to the next page.

On the last page, the animals begin to dance and I use a frame animation to flip through images of the animals moving. It also begins to rain and I created an object animation of rain falling from the top of the canvas.

Since I created a lot of my own images, I decided to package this project on my computer and run it on a local server.

To run this program:

  1. Download .zip file and extract it to your computer
  2. Open a command prompt, and type cd “path to file” (ex: C:\Users\Cassie Howard\Downloads\cmhoward-final-project\template-all)
  3. Then connect to python “python -m http.server”
  4. After it connects, open up http://localhost:8000 in your web browser.

If you get confused on how to move to the next page, remember the different page turning implementations i.e clicking on the jittering objects, completing the animation, or simply waiting (i.e for ten balloons to appear).

cmhoward-final-project

Code to drag objects inspired by:

Draggable Example (written by Daniel Shiffman)

code below! (it’s not NOT working, you just can’t see all of the background images until you connect to a local server!)

sketch-87

//Cassandra Howard
//Section B
//cmhoward@andrew.cmu.edu
//Final Project

//IMAGE VARIABLES
var page1;
var page2;
var page3;
var page4;
var spoon;
var page5;
var page6;
var page7;
var page8;
var page9;
var page10;
var turn_page;
var tomato;

//PAGE COUNTER
var page = 0;

//LOOP THROUGH PAGES
var clickFunctions = [click1, click2, click3, click4, click5, click6, click7, click8, click9, click10];
var drawFunctions = [draw1, draw2, draw3, draw4, draw5, draw6, draw7, draw8, draw9, draw10];

//DRAW1 GLOBAL VARIABLES
//VERTICES POINTS OF SUN
var sunX = [40, 50, 60, 50, 80, 50, 60, 50, 40, 50, 20, 50, 40];
var sunY = [26.5, 53, 80, 53, 53, 53, 26.5, 53, 80, 53, 53, 53, 26.5];

//DRAW2 GLOBAL VARIABLES
//SET Y VALUE OF TOMATOES, INTIALIZE TOMATOES POSITIONS 
var tomatoY1 = 315;
var tomatoY2 = 300;
var tomatoFalling = false;

//DRAW4 GLOBAL VARIABLES
//INTIALIZE SPOON VALUES
var draggingSpoon = false;
var rolloverSpoon = false;
var spoonX;
var spoonY;
var spoonW;
var spoonH;
var offsetSpoonX; 
var offsetSpoonY;

//DRAW6 GLOBAL VARIABLES
//LOAD IMAGE FILES FOR FRAME ANIMATION, CREATE EMPTY ARRAY FOR IMAGES
//INTIALIZE COIN POSITION
var frames = [];
var filenames = [
    "assets/coin_1.png",
    "assets/coin_2.png",
    "assets/coin_3.png",
    "assets/coin_4.png"
    ];
var coinX = 50;
var coinY = 50;
var targetX;
var targetY;
var dx;
var dy;
var distanceFromCoinToTarget;

//DRAW7 GLOBAL VARIABLES
//INTIALIZE APPLE VALUES
var draggingApple = false;
var rolloverApple = false;
var appleX;
var appleY;
var appleW;
var appleH;
var offsetAppleX;
var offsetAppleY;

//DRAW8 GLOBAL VARIABLES
//INTIALIZE APPLE2 VALUES
var draggingApple2 = false;
var rolloverApple2 = false;
var apple2X;
var apple2Y;
var apple2W;
var apple2H;
var offsetApple2X;
var offsetApple2Y;

//DRAW9 GLOBAL VARIABLES
//CREATE EMMPTY ARRAY FOR BALLOONS
var balloons = [];
var bx;
var b; 
var by;


//DRAW10 GLOBAL VARIABLES
//LOAD IMAGES FOR FRAME ANIMATION, CREATE EMPTY ARRAY FOR IMAGES
//CREATE EMPTY ARRAY FOR RAINDROPS
var frames2 = [];
var filenames2 = [
    "assets/dance_1.png",
    "assets/dance_2.png",
    ];
var raindrops = []; 
var rx; 
var ry;


//LOAD BACKGROUND IMAGES FOR EACH PAGE
function setup() {
    createCanvas(480, 480);
    page1 = loadImage("assets/page_1.jpg");
    page2 = loadImage("assets/page_2.jpg");
    tomato = loadImage("assets/tomato.png");
    page3 = loadImage("assets/page_3.jpg");
    turn_page = loadImage("assets/turn_page.png");
    page4 = loadImage("assets/page_4.jpg");
    spoon = loadImage("assets/spoon.png");
    spoonX = 100;
    spoonY = 200;
    spoonW = 50;
    spoonH = 50;
    page5 = loadImage("assets/page_5.jpg");
    page6 = loadImage("assets/page_6.jpg");
    //PUSH IMAGES INTO EMPTY ARRAY
    for (var i = 0; i < filenames.length; i++) {
        frames.push(loadImage(filenames[i]));
    }
    //SET ANIMATION VARIABLES
    coinX = width / 2;
    coinY = height / 2;
    targetX = coinX;
    targetY = coinY;
    page7 = loadImage("assets/page_7.jpg");
    apple = loadImage('assets/apple.png');
    //SET APPLE POSITION
    appleX = 240;
    appleY = 355;
    appleW = 50;
    appleH = 50;
    page8 = loadImage("assets/page_8.jpg");
    //SET APPLE2 POSITION
    apple2X = 100;
    apple2Y = 355;
    apple2W = 50;
    apple2H = 50;
    page9 = loadImage("assets/page_9.jpg");
    //CREATE BALLOON OBJECTS
    for (var i = 0; i < 5; i++) {
        var bx = random(0, width);
        var b = random(50, 80);
        var by = height;
        balloons[i] = makeBalloon(bx, by, b);
    }
    page10 = loadImage("assets/page_10.jpg");
    //PUSH IMAGES INTO EMPTY ARRAY
    for (var i = 0; i < filenames2.length; i++) {
        frames2.push(loadImage(filenames2[i]))
    }
    //CREATE RAINDROP OBJECTS
    for (var i = 0; i < 5; i++) {
        var rx = random(0, width);
        var ry = 0;
        raindrops[i] = makeRaindrop(rx, ry);
    }
    frameRate(5);
}

//CLICK THROUGH PAGES WITH CLICK FUNCTIONS
function mouseClicked() {
    clickFunctions[page]();
}

//CALL PAGE FUNCTIONS
function draw() {
    drawFunctions[page]();
}

//OBJECT DRAGGING FUNCTIONS
function mousePressed() {
    //PAGE 4
    if (mouseX > spoonX & mouseX < spoonX + spoonW && mouseY > spoonY && mouseY < spoonY + spoonH) {
        draggingSpoon = true;
        offsetSpoonX = spoonX - mouseX;
        offsetSpoonY = spoonY - mouseY;
    }

    //PAGE 6 
    if (mouseX > appleX & mouseX < appleX + appleW && mouseY > appleY && mouseY < appleY + appleH) {
        draggingApple = true;
        offsetAppleX = appleX - mouseX;
        offsetAppleY = appleY - mouseY;
    }

    //PAGE 7
    if (mouseX > apple2X & mouseX < apple2X + apple2W && mouseY > apple2Y && mouseY < apple2Y + apple2H) {
        draggingApple2 = true;
        offsetApple2X = apple2X - mouseX;
        offsetApple2Y = apple2Y - mouseY;
    }       
}

//PAGE 1
//MAKE SUN JITTER, CLICK SUN TO MOVE TO NEXT PAGE
function draw1() {
    noStroke();
    background('white');
    image(page1, 0, 0, page1.width, page1.height);
    var sunPoints = sunX.length;
    fill(254, 192, 68);
    beginShape();
    for (var i = 0; i < sunPoints; i++) {
        var sunpX = sunX[i] + random(-2, 2);
        var sunpY = sunY[i] + random(-2, 2);
        vertex(sunpX, sunpY); 
    }
    endShape(CLOSE);
    ellipse(50, 53, 10, 10);
}

function click1() {
    if (mouseX < 60 & mouseX > 40 && mouseY < 60 && mouseY > 40) {
        page = 1;
    };
}


//PAGE 2
//MAKE TOMATOES JITTER, CLICK TOMATOES TO MOVE TO NEXT PAGE
function draw2() {
    noStroke();
    background('white');
    image(page2, 0, 0, page2.width, page2.height);
    if (tomatoFalling === true) {
        tomatoY1 += 10;
        tomatoY2 += 10;
    } else {
        tomatoY1 = random(350, 355);
        tomatoY2 = random(300, 305);
    }

    image(tomato, random(260, 265), tomatoY1, 30, 30);
    image(tomato, random(270, 275), tomatoY2, 30, 30);
    image(tomato, random(315, 320), tomatoY1, 30, 30);
    image(tomato, random(310, 315), tomatoY2, 30, 30);
    image(tomato, random(360, 365), tomatoY1, 30, 30);
    image(tomato, random(355, 360), tomatoY2, 30, 30);

    if (tomatoY1 > page2.height & tomatoY2 > page2.height) {
        page = 2;
    }
}

function click2() {
    if (mouseX < 365 & mouseX > 260 && mouseY > 300 && mouseY < 355) {
        tomatoFalling = true;
    }
}

//PAGE 3
//LOAD BACKGROUND IMAGE, CLICK PAGE TURN ANIMATION TO GO TO NEXT PAGE
function draw3() {
    noStroke();
    background('white');
    image(page3, 0, 0, page3.width, page3.height);
    image(turn_page, 430, 430, turn_page.width, turn_page.height);
}

function click3() {
    if (mouseX < 480 & mouseX > 400 && mouseY < 480 && mouseY > 400) {
        page = 3;
    }
}

//PAGE 4
//COMPLETE DRAGGING SPOON TO MOVE TO NEXT PAGE
function draw4() {
    noStroke();
    background('white');
    image(page4, 0, 0, page4.width, page4.height);

    if (mouseX > spoonX & mouseX < spoonX + spoonW && mouseY > spoonY && mouseY < spoonY + spoonH) {
        rolloverSpoon = true;
    }
    else {
        rolloverSpoon = false;
    }

    if (draggingSpoon) {
        spoonX = mouseX + offsetSpoonX;
        spoonY = mouseY + offsetSpoonY;
    }

    image(spoon, spoonX, spoonY, spoonW, spoonH);

    if (spoonX > 100 & spoonX < 200 && spoonY > 50 && spoonY < 100) {
        page = 4;
    }
}

function mouseReleased() {
    dragging = false;
}

function click4() {

}


//PAGE 5
//LOAD BACKGROUND IMAGE, CLICK PAGE TURN ANIMATION TO FLIP TO NEXT PAGE
function draw5() {
    noStroke();
    background('white');
    image(page5, 0, 0, page5.width, page5.height);
    image(turn_page, 430, 430, turn_page.width, turn_page.height);
}

function click5() {
    if (mouseX < 480 & mouseX > 400 && mouseY < 480 && mouseY > 400) {
        page = 5;
    }
}

//PAGE 6
//TOSS COIN INTO POND, USING FRAME ANIMATION, WHEN COIN REACHES POND, FLIP TO NEXT PAGE
function draw6() {
    noStroke();
    background('white');
    image(page6, 0, 0, page6.width, page6.height);

    dx = targetX - coinX;
    dy = targetY - coinY;
    distanceFromCoinToTarget = sqrt(dx*dx + dy*dy);

    coinX = lerp(coinX, targetX, 0.1);
    coinY = lerp(coinX, targetY, 0.1);

    if (targetX < coinX) {
        push();
        scale(-1, 1);
        image(frames[frameCount % frames.length], -coinX, coinY);
        pop();
    }
    else {
        image(frames[frameCount % frames.length], coinX, coinY);
    }

    if (coinY > 350) {
        page = 6;
    }
}

function click6() {
    targetX = mouseX;
    targetY = mouseY;
}

//PAGE 7
//DRAG APPLE TO LION, WHEN APPLE REACHES LION, FLIP TO NEXT PAGE
function draw7() {
    noStroke();
    background('white');
    image(page7, 0, 0, page7.width, page7.height);

    if (mouseX > appleX & mouseX < appleX + appleW && appleY > appleY && mouseY < appleY + appleH) {
        rolloverApple = true;
    }
    else {
        rolloverApple = false;
    }

    if (draggingApple) {
        appleX = mouseX + offsetAppleX;
        appleY = mouseY + offsetAppleY;
    }

    image(apple, appleX, appleY, appleW, appleH);

    if (appleX > 75 & appleX < 125 && appleY > 300 && appleY < 350) {
        page = 7;
    }
}

function click7() {

}

//PAGE 8
//DRAG APPLE FROM LION TO OWL, WHEN APPLE REACHES OWL, FLIP TO NEXT PAGE
function draw8() {
    noStroke();
    background('white');
    image(page8, 0, 0, page8.width, page8.height);

    if (mouseX > apple2X & mouseX < apple2X + apple2W && apple2Y > apple2Y && mouseY < apple2Y + apple2H) {
    rolloverApple2 = true;
    }
    else {
        rolloverApple2 = false;
    }

    if (draggingApple2) {
        apple2X = mouseX + offsetApple2X;
        apple2Y = mouseY + offsetApple2Y;
    }

    image(apple, apple2X, apple2Y, apple2W, apple2H);

    if (apple2X > 230 & apple2X < 300 && apple2Y > 150 && apple2Y < 200) {
        page = 8;
    }
}

function click8() {

}

//PAGE 9
//CREATE BALLOONS THAT RISE FROM THE BOTTOM OF THE SCREEN, WHEN 10 BALLOONS HAVE BEEN CREATED, MOVE TO NEXT PAGE
function draw9() {
    background('white');
    image(page9, 0, 0, page9.width, page9.height);

    updateAndDisplayBalloons();
    addNewBalloons();

    if (balloons.length > 10) {
        page = 9;
    }
}

function updateAndDisplayBalloons() {
    for (var i = 0; i < balloons.length; i++) {
        balloons[i].move();
        balloons[i].display();
    }
}

function addNewBalloons() {
    var newBalloonProb = .05;
    var b = random(50, 80);
    if (random(0, 1) < newBalloonProb) {
        balloons.push(makeBalloon(random(0, width), height, random(50, 80)));
    }
}

function balloonMove() {
    this.y -= this.speed;
}

function balloonDisplay(){
    push();
    if (this.typeColor < 1) {
        fill(255, 0, 0, 100);
    }
    if (this.typeColor > 1 & this.typeColor < 2) {
        fill(0, 0, 255, 100);
    }
    if (this.typeColor > 2 & this.typeColor < 3) {
        fill(128, 0, 128, 100);
    }
    ellipse(this.x, this.y, this.breadth/1.5, this.breadth);
    stroke('black');
    strokeWeight(1);
    line(this.x, this.y + this.breadth/2, this.x, this.y + 100);
    
    pop();
}

function makeBalloon(bx, by, b) {
    var balloons = {x: bx, y: by, move: balloonMove, display: balloonDisplay, speed: 5, breadth: random(50, 80), place: random(50, 250), type: int(random(0, 3)), typeColor: random(0, 3)}
    return balloons;
}

function click9() {

}

//PAGE 10
//CREATE RAINDROPS FALLING FROM TOP OF CANVAS
//USE FRAME ANIMATION TO MAKE ANIMALS DANCE 
function draw10() {
    background('white')
    image(page10, 0, 0, page10.width, page10.height);

    image(frames2[frameCount % frames2.length], 0, 180);

    updateAndDisplayRaindrops();
    addNewRaindrops();
}

function updateAndDisplayRaindrops() {
    for (var i = 0; i < raindrops.length; i++) {
        raindrops[i].move();
        raindrops[i].display();
    }
}

function addNewRaindrops() {
    var newRaindropProb = .25;
    if (random(0, 1) < newRaindropProb) {
        raindrops.push(makeRaindrop(random(0, width), 0));
    }
}

function raindropsMove() {
    this.y += this.speed;
}

function raindropsDisplay(){
    push();
    fill(135, 206, 250, 100);
    beginShape();
    curveVertex(this.x, this.y);
    curveVertex(this.x-5, this.y+15);
    curveVertex(this.x, this.y+20);
    curveVertex(this.x+5, this.y+15);
    curveVertex(this.x, this.y);
    endShape(CLOSE);
    pop();
}

function makeRaindrop(rx, ry) {
    var raindrops = {x: rx, y: ry, move: raindropsMove, display: raindropsDisplay, speed: 5, place: random(50, 250)}
    return raindrops;
}

function click10() {

}

//END