keuchuka – final project

The video shows how the program should work – words said include “wind” “phone” “black” “yellow” “sock” “shoe” “roof” “ceiling” “cold” “warm” “wind” “water”.

I was trying to create some kind of fuzzy text or spoken word visualizer/analyzer, in a compositional landscape, using the p5.Speech library.
The width of the grayscale boxes is according to the letter of the word.
The morse code is a translation of the letters.
The text is a fuzzy recognition of the words, stretches according to the amplitude.
The ellipses are a representation of amplitude.
The voice recognition does not work too well, but overall I’m satisfied with the effect.

The project requires a local server to run due to the microphone components.
Instructions:
1. Download and extract FINAL PROJECT
2. Install node js
3. type npm install -g http-server into node terminal and enter
4. cd the extracted folder and enter
5. type http-server -c-1 and enter
6. node terminal will give you links
7. enter the link into a browser
8. file should run!

hdw/tlai – Final Project

https://helenxwu.github.io/ –> link to game

https://drive.google.com/a/andrew.cmu.edu/file/d/1NQmUsm_kBniAq7vku2QIYw7QzBkgUOP_/view?usp=sharing –> link to zip file

How to run zip:
1) download file
2) move to desktop
3) open zip folder

4) On mac– open terminal (command+space and search “terminal”)

5) type in “python -m SimpleHTTPServer 8000”

6) go to browser–type in localhost:8000 where the URL would usually go

7) find desktop listing and click on it
8) find downloaded folder and click on it
9) file will load! 🙂

For our final project, Tiffany and I made a dance dance revolution game to the Mii remix. We delved into an entirely new library (the p5js sound extension) and learned a lot about different techniques for signal processing. For the main sound visualizer, we used Fast Fourier Transform algorithm (FFT) to sample the music files’ signals over a period of time, and divided its frequency components to create the bouncing colors that react and move according to note and rhythm.

Additionally, we mapped the volume controls to create new objects under an object function, to randomly generate 4 different types of arrows. We then set a range for the function to work under so the score counter could add points. We also created a start screen and end screen for the game under two separate functions.

thlai/hdw – Project 12 – Final

sketch

// Tiffany Lai (thlai) & Helen Wu (hdw)
// 15-104, Section A
// Project 12 - Final

//var font; // variable for font
var music; // variable for music
var fft; // variable for p5.FFT library
var amp; // variable for p5.Amplitude library
var leftArrows = [];
var opacity = 255;
var scoreCount = 0;
var playMode = 0;

function preload() {
  //font = loadFont('font/slkscr.ttf'); // load font 'silk screen'
  music = loadSound("https://courses.ideate.cmu.edu/15-104/f2017/wp-content/uploads/2017/12/music-2.mp3"); // load music
}

function setup() {
  createCanvas(480, 480);
  fft = new p5.FFT(0.9, 256); // load p5.FFT library
  amp = new p5.Amplitude(); // load p5.Amplitude
}

function draw() {
  background(22, 35, 42);
  circleBeat(); // background sound visualization
  displayTriangles(); // display top triangles
  moveTriangles(); // top triangles go down when pressing specific keys
  generateArrows();

  for (var i = 0; i < leftArrows.length; i++) {
    leftArrows[i].move();
    leftArrows[i].render();
    if (leftArrows[i].y < -500) {
      leftArrows.shift();
    }
  }
  scoreCounter(); // score counter
  endScreen();
  startScreen();
}

//start screen
function startScreen() {
    fill(255, 56, 115, opacity);
    rect(0,0,width,height);
    textSize(12);
      if (frameCount%2 == 0){
        fill(255,opacity);
        //textFont(font);
        textAlign(CENTER);
        textSize(12);
        text("CLICK TO PLAY", width/2, height/2);
    }
}


//music plays
function mouseClicked() {
  displayTriangles(); // display main triangles
  opacity = 0;
  moveTriangles();
  if (playMode == 0) {
    music.play();
    playMode = 'sustain';
  } else {
    playMode = 0;
    music.stop();
   }
}

// background sound visualization
function circleBeat() {
  var spectrum = fft.analyze(); // analyze music spectrum
  // drawing the circle
  push();
  translate(width/2, height/2);
    for (var i = 0; i <  spectrum.length; i++) {
      var angle = map(i, 0, spectrum.length, 0, 360); // map spectrum to degrees
      var spec = spectrum[i];
      var r = 2 * map(spec, 0, 256, 20, 100);
      var x = r * cos(angle);
      var y = r * sin(angle);

      fill(200, i*3, i*5); // fill with gradient
      noStroke();
      ellipse(x, y, 3, 3); // tiny center circles
    }
  pop();
}

//==========CREATE TOP TRIANGLES ==========//
// make triangles object
function makeTriangles (l, d, u, r) {
  var triangles = {
    left: l,
    down: d,
    up: u,
    right: r,
    display: displayTriangles,
    move: moveTriangles
  }
  return triangles;
}

// display triangles
function displayTriangles() {
  fill(255);
  noStroke();
  // draw four anchor triangles
  triangle(115, this.l+66, 154, this.l+88, 154, this.l+44); // left
  triangle(185, this.d+53, 207, this.d+92, 229, this.d+53); // down
  triangle(272, this.u+40, 250, this.u+79, 295, this.u+79); // up
  triangle(325, this.r+44, 325, this.r+89, 364, this.r+66); // right

  // draw 3D part of anchor triangles
  fill(116, 136, 133);
  quad(115, this.l+66, 154, this.l+88, 154, 93, 115, 71); // left
  quad(250, this.u+79, 295, this.u+79, 295, 85, 250, 85); // up
  fill(230, 160, 133);
  quad(185, this.d+53, 185, 62, 207, 102, 207, this.d+92); // down (left)
  quad(207, this.d+92, 207, 102, 229, 62, 229, this.d+53); // down (right)
  quad(325, this.r+89, 325, 94, 364, 71, 364, this.r+66); // right
}

function moveTriangles(){
  // move triangles down when you press specific arrow key
  if (keyIsDown(LEFT_ARROW)) {
    this.l = 3;
  } else if (keyIsDown(DOWN_ARROW)) {
    this.d = 5;
  } else if (keyIsDown(UP_ARROW)) {
    this.u = 4;
  } else if (keyIsDown(RIGHT_ARROW)) {
    this.r = 3;
  } else {
    this.l = 0;
    this.d = 0;
    this.u = 0;
    this.r = 0;
  }
}

//========== GENERATE ARROWS ==========//
function makeArrows(aX, aY, spd, rot) {
  var arrows = {
    x: aX,
    y: aY,
    speed: spd,
    rotateArrow: rot,
    move: moveArrows,
    render: displayArrows,
    generate: generateArrows
  }
  return arrows;
}

function displayArrows() {
  push();
  stroke(0, 200, 200);
  strokeWeight(5);
  noFill();
  translate(this.x, this.y);
  rotate(this.rotateArrow);
  triangle(115, 66, 154, 88, 154, 44);
  pop();
  //triangle(this.x+115, this.y+66, this.x+154, this.y+88, this.x+154, this.y+44);
}

function moveArrows() { // speed of clouds
	this.y -= this.speed;
}

function generateArrows() {
  var vol = amp.getLevel();

  if ((vol > 0.33 & vol < 0.34) || (vol > 0.18 && vol < 0.2) || (vol > 0.03 && vol < 0.032)) {
    var randomizer = int(random(0,4)); // if the volume level is over 0.3
    if(randomizer == 0){
      var newArrow = new makeArrows(0, 420, 4, 0); // make new arrow object
      leftArrows.push(newArrow);
    }

    if (randomizer == 1) {
      var newArrow = new makeArrows(140, 840, 4, 3/2*PI); // make new arrow object
      leftArrows.push(newArrow);
    }

    if (randomizer == 2) {
      var newArrow = new makeArrows(340, 420, 4, 1/2*PI); // make new arrow object
      leftArrows.push(newArrow);
    }

    if (randomizer == 3) {
      var newArrow = new makeArrows(480, 840, 4, PI); // make new arrow object
      leftArrows.push(newArrow);
    }
  }
}

function endScreen() {
  if (music.isPlaying() ) {
    var endOpacity = 0;

  } else {fill(255, 56, 115, endOpacity);
    var endOpacity = 255;
    rect(0, 0, width, height);
    textSize(12);
      if (frameCount%2 == 0){
        fill(255,endOpacity);
        textFont(font);
        textAlign(CENTER);
        textSize(12);
        text("GAME OVER", width/2, height/2);
        text("SCORE: " + scoreCount, width/2, height/2+20);
    }
  }
}

// ========== COUNTER ========== //
function scoreCounter() {
  // draw borders on screen
  noStroke();
  fill(110, 120, 120);
  rect(0, 0, width, 7);
  rect(0, 0, 7, height);
  rect(0, height-7, width, 7);
  rect(width-7, 0, 7, height);
  fill(116, 136, 133);
  quad(182, height, 187, height-25, 292, height-25, 297, height);

  fill(255);
  text("SCORE: " + scoreCount, width/2, 472);
  for (var i = 0; i < leftArrows.length; i++) {
    if((keyIsDown(LEFT_ARROW))) {
      if (leftArrows[i].y > -10 & leftArrows[i].y < 30 && (leftArrows[i].x ==0)) {
        scoreCount = scoreCount + 10;
        leftArrows.shift();
      }
    }
    if(keyIsDown(DOWN_ARROW)){
      if (leftArrows[i].y > 180 & leftArrows[i].y < 220 && (leftArrows[i].x == 140)) {
        scoreCount = scoreCount + 10;
        leftArrows.shift();
      }
    }

    if(keyIsDown(UP_ARROW)){
      if (leftArrows[i].y > -90 & leftArrows[i].y < -50 && (leftArrows[i].x == 340)) {
        scoreCount = scoreCount + 10;
        leftArrows.shift();
      }
    }

    if(keyIsDown(RIGHT_ARROW)){
      if (leftArrows[i].y > 110 & leftArrows[i].y < 150 && (leftArrows[i].x == 480)) {
        scoreCount = scoreCount + 10;
        leftArrows.shift();
      }
    }

}
}

monicah1-Final Project-SectionA

sketch

//monica huang
//monicah1
//final project

var drops = [];
var terrain = [];
var stars = [];
var fireworks = [];
var cols, rows;
var scl = 90;
var w = 500;
var h = 500;
var flying = 0;
var gravity;
var speed;
var particles = [];
var flowfield;
var fr;
var inc = 0.1;
var zoff = 0;
var sound; 



function setup() {
  createCanvas(1100, 500, WEBGL);
  speed = map(mouseX, 2, width, 5, 2);

//throw off lines

for (var i = 0; i < 10; i++) {
    drops[i] = new Drop();
}


//colors
colorMode(HSB, 255);
  cols = floor(width / scl);
  rows = floor(height / scl);
  fr = createP('');

  flowfield = new Array(cols * rows);

  for (var i = 0; i < 10; i++) {
    particles[i] = new Particle();
  }

  
//flowing plain
  cols = w / scl;
  rows = h/ scl;

  for (var x = 0; x < cols; x++) {
    terrain[x] = [];
    for (var y = 0; y < rows; y++) {
      terrain[x][y] = 0; 
    }
  }

}



function draw() {
  background(125,255,0);
  speed = map(mouseX, 0, width, 0, 5);

//throw off lines
  for (var i = 0; i < drops.length; i++) {
    drops[i].fall();
    drops[i].show();
  }

//colors
  var yoff = 0;
  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      var index = x + y * cols;
      var angle = noise(xoff, yoff, zoff) * TWO_PI * 4;
      var v = p5.Vector.fromAngle(angle);
      v.setMag(1);
      flowfield[index] = v;
      xoff += inc;
      stroke(0, 50,170);
    }
    yoff += inc;

    zoff += 0.0003;
  }

  for (var i = 0; i < particles.length; i++) {
    particles[i].follow(flowfield);
    particles[i].update();
    particles[i].edges();
    particles[i].show();
  }

  fr.html(floor(frameRate()));

//flowing plain
  flying -= 0.1;
  var yoff = flying;
  for (var y = 0; y < rows; y++) {
    var xoff = 0;
    for (var x = 0; x < cols; x++) {
      terrain[x][y] = map(noise(xoff, yoff), 0, 1, -100, 100);
      xoff += 0.2;
    }
    yoff += 0.2;
  }
  translate(0, 50);
  rotateX(-PI/3);
  fill(0,0,0);
  translate(-w/2, -h/2);
  for (var y = 0; y < rows-1; y++) {
    beginShape(TRIANGLE_STRIP);
    for (var x = 0; x < cols; x++) {
      vertex(x*scl, y*scl, terrain[x][y]);
      vertex(x*scl, (y+1)*scl, terrain[x][y+1]);
    }
    endShape();
  }

}

//---------------------------------------------------------------------------

// lines
function Drop() {
  this.x = random(width*2);
  this.y = random(-500, -500);
  this.z = random(0, 10);
  this.len = map(this.z, 0, 10, 0, 30);
  this.yspeed = map(this.z, 0, 10, 1, 20);

  this.fall = function() {
    this.y = this.y + this.yspeed;
    var grav = map(this.z, 0, 60, 0, 0.6);
    this.yspeed = this.yspeed + grav;

    if (this.y > height) {
      this.y = random(-200, -200);
      this.yspeed = map(this.z, 0, 20, 4, 10);
    }
  }

  this.show = function() {
    var thick = map(this.z, 0, 20, 1, 3);
    strokeWeight(thick);
    stroke(random(0,255), random(0,255), random(0,255));
    line(this.x, this.y, this.x, this.y+this.len);
  }
}

//colors
function Particle() {
  this.pos = createVector(random(width), random(height));
  this.vel = createVector(0, 0);
  this.acc = createVector(0, 0);
  this.maxspeed = 2;
  this.h = 0;

  this.prevPos = this.pos.copy();

  this.update = function() {
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }

  this.follow = function(vectors) {
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y * cols;
    var force = vectors[index];
    this.applyForce(force);
  }

  this.applyForce = function(force) {
    this.acc.add(force);
  }

  this.show = function() {
    stroke(random(0,255), random(0,255), random(0,255));
    this.h = this.h + 1;
    if (this.h > 255) {
      this.h = 0;
    }
    strokeWeight(1);
    line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
    this.updatePrev();
  }

  this.updatePrev = function() {
    this.prevPos.x = this.pos.x;
    this.prevPos.y = this.pos.y;
  }

  this.edges = function() {
    if (this.pos.x > width) {
      this.pos.x = 0;
      this.updatePrev();
    }
    if (this.pos.x < 0) {
      this.pos.x = width;
      this.updatePrev();
    }
    if (this.pos.y > height) {
      this.pos.y = 0;
      this.updatePrev();
    }
    if (this.pos.y < 0) {
      this.pos.y = height;
      this.updatePrev();
    }

  }

}





I am inspired by space, speed, and motion in galaxy. I am interested in creating 3d dimensional space and motion with 2 dimensional lines and colors.

ssharada-final-project-section-a

sketch

https://alpha.editor.p5js.org/shariwa/sketches/H16PfJF-G

Since this code has sounds, the WordPress account doesn’t display it properly. Above is a link to the p5.js alpha editor where you can properly view my code. Once at the website click the play button on the top left corner of the screen

My project looked at combining motion graphics and sounds. I wanted the graphics to work such that more was revealed as you moved around the canvas – everything is made out of two colours so as the mouse moves in the horizontal direction, you get to view more of the graphics as a differentiation is created between the background and the actual graphics.

I had an issue with running the local server on my laptop so I used the oscillation program from p5.js to get a sine curve amplitude and frequency to create a sound that my motion graphics responded to. The larger objects respond to the sound that is generated. The rippling, striped circle responds to the silence in between the beep noises. The white ellipse curve is its own thing that just renders what a traditional sine curve looks like.

When the canvas is clicked on, the noise stops and the motion graphics continue. To restart the noise you have to refresh the page.


^mouseX at at 0


^mouseX at maximum width

hannahk2-Final Project

Instructions to run the file:

1)Download and unzip the file below

spider

2) run a local server and access the file this way (it will not work otherwise unless you download the p5 editor and open it using the play button)

3) wait about 2 minutes before clicking the game to start. There are a lot of graphics so it takes a really long time to load so I would just keep clicking around the top of the screen after about 2 minutes until it loads and lets you play

4)refresh the page to restart if u lose and enjoy! Also don’t come too close to the edges of the screen.

Here is the embedded code just in case:

sketch

//Hannah Kim
//Section A
//hannahk2@andrew.cmu.edu
//Final Project

//variable for background image
var bg;
//variable for rain particles
var particles;
//variable for portal
var portalSprite;
//variable for random portal x position
var ran1;
//variable for random portal y position
var ran2;
//variable for spiders group
var spiders;

//arrays within array storing specific positions 
//of spiders on top of lillypads
var spiderPos = [
    [103, 242],
    [155, 260],
    [134, 292],
    [160, 311],
    [223, 290],
    [207, 299],
    [192, 304],
    [200, 328],
    [185, 322],
    [193, 362],
    [205, 347],
    [220, 374],
    [172, 377],
    [193, 405],
    [166, 399],
    [240, 422],
    [215, 428],
    [182, 430],
    [140, 410],
    [157, 339],
    [151, 362],
    [130, 315],
    [113, 347],
    [229, 413],
    [125, 377],
    [101, 389],
    [82, 356],
    [37, 397],
    [110, 429],
    [88, 440],
    [223, 459],
    [176, 468],
    [197, 488],
    [275, 450],
    [261, 436],
    [220, 476],
    [236, 518],
    [191, 536],
    [146, 546],
    [160, 518],
    [92, 480],
    [260, 543],
    [236, 582],
    [269, 284],
    [255, 289],
    [252, 313],
    [229, 314],
    [251, 334],
    [254, 378],
    [281, 384],
    [295, 271],
    [303, 286],
    [285, 300],
    [289, 331],
    [291, 352],
    [311, 338],
    [322, 318],
    [320, 292],
    [333, 340],
    [321, 380],
    [346, 361],
    [332, 403],
    [345, 429],
    [308, 428],
    [334, 449],
    [377, 415],
    [373, 391],
    [320, 492],
    [312, 476],
    [349, 484],
    [345, 502],
    [337, 548],
    [318, 529],
    [376, 510],
    [406, 375],
    [381, 352],
    [361, 301],
    [85, 539],
    [54, 575],
    [101, 610],
    [396, 301],
    [416, 317],
    [398, 338],
    [445, 325],
    [436, 352],
    [416, 397],
    [387, 448],
    [384, 481],
    [457, 437],
    [435, 484],
    [470, 352],
    [431, 555]
];

//sets normal game state with timer at 0
var gameState = "menu";
var timer = 0;

//preloads background image
function preload() {
    bg = loadImage("assets/spiderbg.png");
}

function setup() {
    createCanvas(500, 668);
    //sets random values for x position of portal
    ran1 = random(100, 400);
    //sets random values for y position of portal
    ran2 = random(550, 600);
    //creates sprite for the portal at random position 
    //and assigns animation
    portalSprite = createSprite(ran1, ran2);
    portalSprite.addAnimation("normal", "assets/portal0000.png", "assets/portal0002.png")
        //scales the portal to be smaller
    portalSprite.scale = .2;
    //slows down the frame rate of the animation
    portalSprite.animation.frameDelay = 20;

    //creates particle group for rain
    particles = new Group();
    //assign new sprites to groups
    for (var i = 0; i < 100; i++) {
        //puts all creation and initialization instructions in a 
        //premade function found at bottom of code
        createParticle();
    }

    //creates sprite group for spiders
    spiders = new Group();
    //for loop to create all spiders at positions in position array
    for (var i = 0; i < spiderPos.length; i++) {
        //creates spider sprites at specified positions
        var s = createSprite(spiderPos[i][0], spiderPos[i][1]);
        //animation for spiders in normal state
        s.addAnimation("playing", "assets/spider0000.png", "assets/spider0009.png");
        //plays the spider animation starting at different frames
        var f = floor(random(0, s.animation.getLastFrame()));
        s.animation.changeFrame(f);
        //animation for spiders when they're looking at you before game ends
        s.addAnimation("looking", "assets/spider0010.png", "assets/spider0012.png");
        //sets the circle around the spider which ends the game when touched
        s.setCollider("circle", 0, 0, 90);
        //increases the size of the spider as the y position increases
        //by indexing into the position array and multiplying by decimal
        var spiderSize = 0.04;
        s.scale = spiderSize * .005 * (spiderPos[i][1]);
        //trigger the looking function + looking animation when
        //mouse goes over the spider collider
        s.onMouseOver = function() {
                //changes animation to looking animation
                looking(spiders);
            }
        //add spider sprites
        spiders.add(s);
    }
}

//function for when you touch a spider and
//it looks at you and the game ends
function looking(g) {
    if (gameState == "game") {
        for (var i = 0; i < g.length; i++) {
            var sp = g[i];
            sp.changeAnimation("looking");
            //delays frame rate of animation
            sp.animation.frameDelay = 10;
        }
        gameState = "looking";
        //adds timer to countdown to game over state 
        //after the looking animation is triggered
        timer = 60;
    }
}

function draw() {
    background(255);
    //sets up the menu state with text and background
    if (gameState == "menu") {
        s = "OH NO! You have fallen down a sewer and have been plunged into a fantastical realm. Reach the portal swiftly to get back to the human realm without coming into contact with the spiders. Good luck! Click anywhere to begin."
        background(0)
        textSize(30);
        fill(156, 183, 226)
        text(s, 10, 10, 400, 400);
        s2 = "This fantasy realm, The Conjured Isles, is inhabited by hundred eyed spiders who are extremely wise. They usually pass their time playing in never ending rain. They live ontop of lillypads in the blood river. They are currently ruled by a mysterious creature that looms over the realm atop a black cloud, whom the people respect intensely."
        textSize(20);
        fill(156, 183, 226)
        text(s2, 10, 450, 400, 600);
        //on clicking on the screen the game starts + goes into "game" state
        if (mouseIsPressed) {
            gameState = "game";
        }
    }
    //draw sprites if the game state changes from menu
    if (gameState != "menu") {
        drawSprites();
        //counts down from timer once game state goes into "looking" and
        //at 0 the game state changes to "gameOver"
        if (gameState == "looking") {
            timer--;
            if (timer <= 0) {
                gameState = "gameOver";
            }
        }
        //sets up the game over state with text and background
        if (gameState == "gameOver") {
            background(0);
            s3 = "You were seen and banished by the spiders before you could reach the human realm. Better luck next time!"
            textSize(30);
            fill(156, 183, 226)
            text(s3, 10, 10, 400, 400);
            //if game state is not "gameOver" display normal background
        } else {
            image(bg);
            //if the mouse is within the bounds of the portal, 
            //change game state to won
            if (gameState == "game" & mouseX < ran1 + 25 && mouseX > ran1 - 25 &&
                mouseY < ran2 + 25 && mouseY > ran2 - 25) {
                gameState = "won";
            }
            //if the mouse gets too close to the left and right side
            //and the bottom side, (for cheaters), end game
            if (gameState == "game" & mouseX < 10 || mouseX > width - 10 || mouseY > height - 10) {
                gameState = "gameOver"
            }
            //sets up the won state with text and background
            //removes sprites
            if (gameState == "won") {
                background(0);
                s4 = "You reached successfully the portal and returned to the human realm! Congrats!"
                textSize(30);
                fill(156, 183, 226)
                text(s4, 10, 10, 400, 400);
                s.remove();
            }
            //code to draw the rain particles
            for (var i = 0; i < particles.length; i++) {
                //stores the particle in a temporary variable called p
                var p = particles[i];
                //scales it down
                p.scale = 0.15;
                //moves all the y positions of the particles down
                //for rain falling effect
                p.position.y += 10;
                //wraps particle to the top when it reaches the bottom
                if (p.position.y > height) {
                    p.position.y = -50;
                }
            }
            //draw all sprites
            drawSprites();
        }
    }
}
//function to create the rain particle
function createParticle() {
    //creates a sprite at a random position
    var newParticle = createSprite(random(0, width), random(0, height));
    //assigns an animation
    newParticle.addAnimation("falling", "assets/cloud.png");
    //adds it to the particle group
    particles.add(newParticle);
}

Here are screenshots of the game also:

^ the menu page

^the game in its normal state

^ the game when the player touches a spider

^ the game over state

^ the winning state

For this project I wanted to create a game based mostly on graphics, visuals, and backgrounds. I wanted to create a game where the player has to navigate through a tricky trap-like environment. The player has to avoid coming into contact with the inhabitants of an imaginary realm while hurrying to reach a portal to get back to the human realm. They have to navigate through a mob of spiders resting on top of lillypads without touching them and being seen. This project was really fun for me, despite having to code the positions of the spiders individually so that they would fit nicely on top of the lillypads that I chose. I really enjoyed making the background in particular, which I made for this project by painting first in watercolor, then scanning into photoshop and drawing ontop of it digitally. I also really enjoyed coming up with the narrative aspect of the project, and the world building.

jknip-Final-Project-SectionA

sketch

/*Jessica Nip
Section A
jknip@andrew.cmu.edu
Project-12
*/

//define global variables------------------------------------------------------
var x;
var y;
var dx;
var dy;
var current_block;
var old_blocks = [];
var blockw = 90;
var blockh = 70;
var clicked = false;
var score = 0;
var gameover = false;
var windowmargin = 10;
var start_speed;
var bground = ["https://i.imgur.com/gZ7wNWJ.png"];
var intro = "STACK THE HIGHEST TOWER.";

//colors
var darkblue;
var lightpink;
var lightred;
var grey;
var grey2;
var grey3;
var grey4;
var canvasw;
var canvash;


//---------------------------------------------------------------------------
function preload() {
    //background skyline
    bground = loadImage(bground[0]);
}


//---------------------------------------------------------------------------
function setup() {
    //define initial canvas settings
    createCanvas(350, 600);
    x = width/2;
    y = 10;
    dx = 1;
    dy = 0;
    frameRate(30);
    canvash = height;
    canvasw = width;
    start_speed = 1;

    //define color RGB
    darkblue = color(44,62,80);
    lightpink = color(252,146,179);
    lightred = color(252,67,73);
    grey = color(225);
    grey2 = color(215,218,219);
    grey3 = color(160);
    grey4 = color(200);

    //call object function
    current_block = new blockFeeder(width/2, 10, blockw,blockh,start_speed);
}


//---------------------------------------------------------------------------
function draw() {
    background(grey2);

    //skyline
    fill(darkblue);
    image(bground, 0, height*(3/5)-25, width, height/3);
    rect(0,height*(8/10), width, height);

    //sun
    fill(lightred);
    ellipse(width*(3/4),200,70,70);

    //gameover screen
    if (gameover){
        fill(darkblue);
        rect(0,0,width,height);
        fill(255);
        textSize(22);
        textStyle(BOLD);
        text("GAME OVER", width/4, height/2-height/30);
        textStyle(NORMAL);
        textSize(14);
        text("Your tower was " + score + "/F.", width/4, height/2);
    } 

    //stacking blocks correctly
    else {
        current_block.draw();
        current_block.update();

        for (var i = 0; i < old_blocks.length; i++) {
            if (score > 3){
                old_blocks[i].y += 2;
            }
            old_blocks[i].draw();
        }

        //gameover if blocks not stacked in same column
        if (score > 0){
            if (old_blocks[score-1].y > height){
                gameover = true;
            }      
        }

        countScore();

        //if block hits bottom of canvas, push block into old blocks array
        if (current_block.hitbottom) {
            old_blocks.push(current_block);
            start_speed += 1;
            current_block = new blockFeeder(width/2, 10, blockw,blockh,start_speed);
        }
    }
}


//create object-------------------------------------------------------------
function blockFeeder(x, y, width, height, speed) {
    this.x = x;
    this.y = y;
    this.dx = speed;
    this.dy = 0;
    this.width = width;
    this.height = height;
    this.isclicked = false;
    this.hitbottom = false;
    this.draw = function() {
    
    //crane (make it not fall with clicked block)
    if (!this.isclicked){
        fill(darkblue);
        noStroke();
        rect(this.x + this.width/2, this.y - windowmargin, this.width/6, this.height/6); 
    }

    //floor
    fill(grey3);
    stroke(grey);
    rect(this.x, this.y, this.width, this.height);

    //block window decor
    fill(grey);
    rect(this.x + windowmargin, this.y + windowmargin*2, this.width/3, this.height/2);
    rect(this.x + windowmargin*5, this.y + windowmargin*2, this.width/3, this.height/2);
    fill(grey4);
    stroke(grey);
    rect(this.x + windowmargin, this.y + windowmargin*2, this.width/3, this.height/3);
    rect(this.x + windowmargin*5, this.y + windowmargin*2, this.width/3, this.height/3);
    }

    //create horizontal crane movement
    this.update = function() {
        this.x += this.dx;
        this.y += this.dy;
        if ((this.x + this.width) > canvasw) {
            this.dx = -this.dx;
            } else if (this.x < 0) {
            this.dx = -this.dx;
        }

        //make new block stack on previous height boundary
        if (score == 0){
            if (this.y + this.height > canvash) {
                this.dy = 0;
                this.hitbottom = true;
                this.y = canvash - this.height;
            }
        }

        //check if new block collides with bottom block accordingly
        else {
            if (this.y + this.height > old_blocks[score-1].y) {
                if (abs(this.x-old_blocks[score-1].x) < blockw/2){
                    this.dy = 0;
                    this.hitbottom = true;
                    this.y = old_blocks[score-1].y - this.height;
                }
                else {
                    this.dy = 0;
                    this.hitbottom = true;
                    this.y = old_blocks[score-1].y - this.height;
                    gameover = true;
                }

            }
        }
    }

    //move block to bottom of canvas when clicked
    this.pressedButton = function(){
        this.isclicked = true;
        if (!this.hitbottom){
            this.dx = 0;
            this.dy = 10;
        }
    }

}


//---------------------------------------------------------------------------
function countScore(){
    //define type settings
    strokeWeight(1);
    fill(255);
    noStroke();
    textSize(20);
    textStyle(NORMAL);
    text(score + "/F", width - 45, height - 20);
    textSize(13);
    textStyle(BOLD);
    text(intro, windowmargin*2, height-20);

    //when block stacks, add score
    if (current_block.hitbottom) {
        score += 1;
    }

}


//---------------------------------------------------------------------------
function mousePressed() {
    //follow block rules when mouse is pressed
    current_block.pressedButton();
    //remove intro when mouse pressed
    intro = " ";
}


Instructions
Stack the highest tower by aligning blocks with at least 50% accuracy! The horizontal and vertical speed increases will make the level harder over time. Your tower height will also be recorded.

Description
Inspired by classic tower stack mobile games, I wanted to create an alternative version of it using a simple horizontal “crane”, with pressure given to the player from its increased speed over time. As the player begins to stack a higher tower, original blocks also begin to slide downwards, creating more time pressure for players. I also wanted to explore creating minimalistic graphics for a challenging, interactive game.

mmiller5-Final Project

Instructions: Press any key to continue when text is finished scrolling.  Click on choice boxes to select choice.

sketch

//choice variables
var choiceNow = false;
var choiceSoon = false;
var lastChoice = 1;
var buttonChoice = [0, 0, 0, 0, 0];
var choice1 = ["Go Forward", "Feel Around", "Stay Still"];
var choice2 = ["Go Back", "Kick", "Fall Down"];
var choice3 = ["Scarlet", "Cerulean", "Emerald", "None"];
var doorUnlocked = false;

//text variables
var textAll = []; //array containing all text objects
var textList = [
    //0-2
    "You awake to find yourself in a dark room.",
    "You can't see anything, probably because it is dark.",
    "What are you going to do?",
    //3-5
    "You decide to move forward, not that it really matters what direction you move in because it all looks the same.",
    "This area of the room smells like apples; it makes you nauseous.",
    "Now what are you going to do?",
    //6-9
    "You decide that this area isn't as good as the last one, so you walk backwards to whence you came.",
    "As you moonwalk to your origin, the apple smell dissipates, easing your uneasiness.",
    "Now back in your starting area, you feel a calm serenity wash over your eyebrows.",
    "What are you going to do?",
    //10-13
    "You decide to wave your arms frantically, almost instantly thwacking a wall to your left.",
    "After massaging your injured hand, you run your hand across the wall and notice some buttons.",
    "There are 3 buttons, and you are stupidly confident that you know their colors even though it is pitch black.",
    "Which button do you wish to press?",
    //14-15
    "You hear a satisfying 'Click' as you press the Scarlet button.",
    "Which button do you wish to press?",
    //16-17
    "The Cerulean button gives you much resistance, but you eventually manage to become victorious and press the button.",
    "Which button do you wish to press?",
    //18-19
    "You feel an exhilerating rush of energy enter your body through your fingertip as you press the Emerald button.",
    "Which button do you wish to press?",
    //20-22
    "You decide that the buttons aren't worthy of your tender carresses and go back.",
    "You are back where you were before, it's just as dark as before.",
    "What are you going to do?",
    //23-29
    "You decide that this is probably all a dream and that the proper course of action is to do nothing.",
    "After doing nothing for so long, you become drowsy, eventually falling asleep on the floor.",
    "zzzzzzzzz",
    "...",
    "You awake to find yourself in a dark room.",
    "You can't see anything, probably because it is dark.",
    "What are you going to do?",
    //30-34
    "You decide to vent your frustrations by violently thrusting your foot forward, only for it to meet a metal object.",
    "The metal object wins, leaving your foot in a sorry state.",
    "You examine the metal object more closely and discover that it's a door, but it's locked.",
    "You recover from your defeat and contemplate your course of action.",
    "What are you going to do?",
    //35-40
    "You decide to do some pushups, but your arms are too weak and you fall to the floor.",
    "When your nose crunches against the cold ground, you feel some engravings scratch against you.",
    "Rubbing your fingers across the floor, you feel some words.",
    "'Blue', 'Green', 'Blue', 'Red', 'Green'.",
    "Wondering what these words mean, you stand back up and wipe the blood from your upper lip.",
    "What are you going to do?",
    //41-43
    "You decide to cautiously extend your foot outwards, but there is nothing there to challenge its movement.",
    "You then advance through the empty space, no metal object impeding your progress.",
    "Did you escape? Or is this just the beginning?"];
var textNum = 0;
var currentText = 0;
var count = 0;
var letterGap = 10;
var timeGap = 3; //timing between letter placements
var textTop; //top of text box
var textLimit; //length of displayed text

function setup() {
    createCanvas(480, 360);
    textSize(20);
    textTop = 2 * height / 3;
    textAlign(CENTER);
    textAssign();
}
function draw() {
    currentText = textNum;
    background(0);
    present(1, 2, choice1, 3, 2, 10, 4, 23, 9);
    present(2, 5, choice2, 6, 3, 30, 10, 35, 11);
    present(3, 9, choice1, 3, 2, 10, 4, 23, 9);
    present4();
    present5();
    present6();
    present7();
    present(8, 22, choice1, 3, 2, 10, 4, 23, 9);
    present(9, 29, choice1, 3, 2, 10, 4, 23, 9);
    if (lastChoice == 10) {
	if (doorUnlocked) {
	    lastChoice = 12;
	    textNum = 41
	} else {
	    present(10, 34, choice2, 6, 3, 30, 10, 35, 11);
	}
    }
    present(11, 40, choice2, 6, 3, 30, 10, 35, 11);
    present(12);
    unlockDoor();
}
//put each text line into an object
function textAssign() {
    for (var i = 0; i < textList.length; i ++) {
	var newText = {words: textList[i],
		       scroll: textScroll,
		       next: nextText}
	textAll.push(newText);
    }
}
//access the line of text and display it in a scroll style
function textScroll() {
    fill(255);
    strokeWeight(0);
    stroke(255);
    textSize(2 * letterGap);
    var xPos = 0;
    var yPos = 0;
    textLimit = min((count / timeGap), this.words.length);
    for (var i = 0; i < textLimit; i ++) {
	xPos += letterGap;
	//if overflow, start a new line
	if (25 + letterGap + xPos > width - 25 - letterGap) {
	    xPos = letterGap;
	    yPos += letterGap * 2;
	}
	text(this.words.charAt(i), 25 + letterGap + xPos,
	     textTop + letterGap * 2 + yPos);
    }
    count = min(count + 1, this.words.length * timeGap);
    if (count == this.words.length * timeGap & choiceSoon == true) {
	choiceNow = true;
    } else {
	choiceNow = false;
    }
}
//perform text functions
function textStep(t) {
    textAll[t].scroll();
    textAll[t].next();
    textBox();
}
//displays the text box
function textBox() {
    noFill();
    strokeWeight(3);
    stroke(255);
    rectMode(CORNERS);
    rect(25, textTop, width - 25, height - 25);
}
//make it so when you press a key, next text comes in
function nextText() {
    if (count == this.words.length * timeGap
	& keyIsPressed == true
	&& textNum != textList.length - 1
	&& choiceSoon == false) {
	textNum += 1
	count = 0;
    }
}
//display the choice options in multiple boxes
function choiceDisplay(choice) {
    for (var i = 0; i < choice.length; i ++) {
	var boxSide = (width - 25 * (choice.length + 1)) / choice.length;
	noFill();
	strokeWeight(2);
	stroke(255);
	rectMode(CORNER);
	rect(25 * (i + 1) + (boxSide * i),
	     height / 3 - boxSide / 2, boxSide, boxSide);
	fill(255);
	strokeWeight(1);
	text(choice[i], 25 * (i + 1) + (boxSide * i) + boxSide / 2, height / 3);
    }
}
//allow player to make a choice depending on click location
function choiceAction(choice) {
    var boxSide = (width - 25 * (choice.length + 1)) / choice.length;
    if (mouseIsPressed) {
	if (mouseY > height / 3 - boxSide / 2 &
	    mouseY < height / 3 + boxSide / 2) {
	    for (var i = 0; i < choice.length; i ++) {
		if (mouseX > 25 * (i + 1) + (boxSide * i) &
		    mouseX < 25 * (i + 1) + (boxSide * i) + boxSide) {
		    return i;
		}
	    }
	}
    }
}
//button panel
function present4() {
    if (lastChoice == 4) {
	textStep(currentText);
	if (currentText == 13) {
	    choiceSoon = true;
	    if (choiceNow == true) {
		choiceDisplay(choice3);
		var choice = choiceAction(choice3);
		if (choice == 0) {
		    textNum = 14;
		    lastChoice = 5;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(1);
		} else if (choice == 1) {
		    textNum = 16;
		    lastChoice = 6;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(2);
		} else if (choice == 2) {
		    textNum = 18;
		    lastChoice = 7;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(3);
		} else if (choice == 3) {
		    textNum = 20;
		    lastChoice = 8;
		    count = 0;
		}
	    }
	} else {
	    choiceSoon = false;
	}
    }
}
//scarlet button press
function present5() {
    if (lastChoice == 5) {
	textStep(currentText);
	if (currentText == 15) {
	    choiceSoon = true;
	    if (choiceNow == true) {
		choiceDisplay(choice3);
		var choice = choiceAction(choice3);
		if (choice == 0) {
		    textNum = 14;
		    lastChoice = 5;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(1);
		} else if (choice == 1) {
		    textNum = 16;
		    lastChoice = 6;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(2);
		} else if (choice == 2) {
		    textNum = 18;
		    lastChoice = 7;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(3);
		} else if (choice == 3) {
		    textNum = 20;
		    lastChoice = 8;
		    count = 0;
		}
	    }
	} else {
	    choiceSoon = false;
	}
    }
}
//cerulean button press
function present6() {
    if (lastChoice == 6) {
	textStep(currentText);
	if (currentText == 17) {
	    choiceSoon = true;
	    if (choiceNow == true) {
		choiceDisplay(choice3);
		var choice = choiceAction(choice3);
		if (choice == 0) {
		    textNum = 14;
		    lastChoice = 5;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(1);
		} else if (choice == 1) {
		    textNum = 16;
		    lastChoice = 6;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(2);
		} else if (choice == 2) {
		    textNum = 18;
		    lastChoice = 7;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(3);
		} else if (choice == 3) {
		    textNum = 20;
		    lastChoice = 8;
		    count = 0;
		}
	    }
	} else {
	    choiceSoon = false;
	}
    }
}
//emerald button press
function present7() {
    if (lastChoice == 7) {
	textStep(currentText);
	if (currentText == 19) {
	    choiceSoon = true;
	    if (choiceNow == true) {
		choiceDisplay(choice3);
		var choice = choiceAction(choice3);
		if (choice == 0) {
		    textNum = 14;
		    lastChoice = 5;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(1);
		} else if (choice == 1) {
		    textNum = 16;
		    lastChoice = 6;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(2);
		} else if (choice == 2) {
		    textNum = 18;
		    lastChoice = 7;
		    count = 0;
		    buttonChoice.shift();
		    buttonChoice.push(3);
		} else if (choice == 3) {
		    textNum = 20;
		    lastChoice = 8;
		    count = 0;
		}
	    }
	} else {
	    choiceSoon = false;
	}
    }
}

//door open exit
function present12() {
    if (lastChoice == 12) {
	choiceSoon = false;
	textStep(currentText);
    }
}

//general present function, isn't used for button presses
function present(lastC, choiceLine, choiceNum, newTextNum0, newLastC0, newTextNum1,
		 newLastC1, newTextNum2, newLastC2) {
    if (lastChoice == lastC) {
	textStep(currentText);
	if (currentText == choiceLine) {
	    choiceSoon = true;
	    if (choiceNow == true) {
		choiceDisplay(choiceNum);
		var choice = choiceAction(choiceNum);
		if (choice == 0) {
		    textNum = newTextNum0;
		    lastChoice = newLastC0;
		    count = 0;
		} else if (choice == 1) {
		    textNum = newTextNum1;
		    lastChoice = newLastC1;
		    count = 0;
		} else if (choice == 2) {
		    textNum = newTextNum2;
		    lastChoice = newLastC2;
		    count = 0;
		} else if (choice == 3) {
		    textNum = newTextNum3;
		    lastChoice = newLastC3;
		    count = 0;
		}
	    }
	} else {
	    choiceSoon = false;
	}
    }
}

function unlockDoor() {
    if (buttonChoice[0] == 2 &
	buttonChoice[1] == 3 &&
	buttonChoice[2] == 2 &&
	buttonChoice[3] == 1 &&
	buttonChoice[4] == 3) {
	doorUnlocked = true;
    }
}

This project was pretty fun to work on, but I’m actually a bit disappointed in it.  It’s a text-based adventure with a simple non-puzzle that’s really more of a proof of concept.

akluk-final-project

For my project I mainly based my project on whack a mole game combined with the pokemon that everyone loves, Diglet. The game lasts for 60 sec and during time the player would want to hit as many diglets as possible. Once the game ends the user can press r to restart the game. Hope you enjoy the game!

Screenshot of the game

sketch

//Alvin Luk
//Section A
//akluk@andrew.cmu.edu
//Final Project

//initialize constants and variables
//number of rows of diglets in the canvas
var rows = 3;

//body height of the diglet
var diglet_h = 30;
//number of diglets in the game
var num_diglets = 11;
//array to contain the diglet objects
var diglets = [];
//temporary dummie variable to help push all the diglets 
var temp_diglet;
//number of diglets the player has hit in a single run of game/score
var num_hit;
//number of 0.5 sec passed elapsed
var time_elapsed = 0;
//duration of game 60sec
var game_time = 120;
//whether the game has ended
var ended = 0;
//hammer mode to determine if hammer is down or up
var mode; 
//start position for even rows
var startx1 = 60;
//start position for odd row
var startx2 = 120;
//spacing with each diglet
var spacing = 120;
//height spacing
var dy = 90;


function setup() {
    createCanvas(480, 360);
    //creates the diglets in the right positions
    // and pushes it into the array of diglets
    for (var i = 0; i < rows; i++) {
        //even rows
        if ((i % 2) == 0){
            for (var j = startx1; j < width; j += spacing){
                temp_diglet = new diglet(j,dy*(i+1));
                diglets.push(temp_diglet);
            }
        }
        //odd rows
        else {
            for (var j = startx2; j < width; j += spacing){
                temp_diglet = new diglet(j,dy*(i+1));
                diglets.push(temp_diglet);
            }
        }
    }
    //initialize score for player
    num_hit = 0;
    //update the diglets ever half second to determine if they pop up
    //and update timer every 0.5 sec
    setInterval(function(){
        for (var index = 0; index < num_diglets; index ++){
            diglets[index].update();
        }
        time_elapsed += 1;
    }, 500);
}

function draw() {
    background(40,180,40);
    noStroke();
    //change the display of the hammer 
    if (mouseIsPressed){
        mode = 1;
    }
    else {
        mode = 0;
    }

    //end the game when the timer has ended 
    if (time_elapsed >= game_time){
        ended = 1;
    }
    //if game has not ended, draw the holes for the diglets in the correct location
    if (ended == 0){
        for (var i = 0; i < rows; i++) {
            //odd rows
            if ((i % 2) == 0){
                for (var j = 60; j < width; j += 120){
                    drawHole(j,dy*(i+1));
                }
            }
            //even rows
            else {
                for (var j = 120; j < width; j += 120){
                    drawHole(j,dy*(i+1));
                }
            }
        }
        //draw every diglet in the array of diglets
        for (var index = 0; index < num_diglets; index ++){
            diglets[index].draw();
        }   
        //draw hammer in passive position     
        if (mode == 0) {
            fill(130,82,1);
            rect(mouseX-5,mouseY-25,10,50);
            fill(120);
            rect(mouseX-25,mouseY-35, 50,20);
        }
        //draw hammer in active position
        else {
            fill(130,82,1);
            rect(mouseX,mouseY-5,50,10);
            fill(120);
            rect(mouseX-10,mouseY-25, 20,50);
        }

        //display score and time left for the game
        fill(255);
        textSize(15);
        text("Score : " + num_hit, 400,340);
        text("Time Left : " + (game_time-time_elapsed)/2,5,340);
    }
    //game over screen
    else {
        fill(0);
        rect(0,0,width,height);
        fill(255);
        text("Game Over!", width/2 - width/10, height/2);
        text("Final Score : " + num_hit, width/2 - width/10,height/2 + height/15);
        text("Press R to restart", width/2 - width/10, height/2 + 2*height/15);
    }

}

//draw the hole sorry for much random numbers to make it look natural
function drawHole(x,y){
    fill(0);
    ellipse(x,y,80,40);
    fill(103,104,76);
    ellipse(x-40,y,22,12);
    ellipse(x+40,y,22,12);
    fill(90,77,65);
    ellipse(x-32,y+8,20,12);
    ellipse(x+28,y+8,24,14);
    fill(119,120,119);
    ellipse(x-22,y+13,20,12);
    ellipse(x+12,y+16,24,15);
    fill(100,100,100);
    ellipse(x-4,y+18,28,15);   
}


//object of diglet 
function diglet(x,y,duration){
    //base variables
    this.x = x;
    this.y = y;
    this.duration = duration;
    //draw the diglet, with eyes and body
    this.draw = function() {
        if (this.duration > 0) {
            //brown of diglet
            fill(181,147,119);
            rect(this.x-diglet_h/2,this.y-diglet_h,diglet_h,diglet_h);
            ellipse(this.x,this.y-diglet_h,diglet_h,diglet_h);
            
            fill(0);
            ellipse(this.x-diglet_h/6,this.y-diglet_h,3,6);
            ellipse(this.x+diglet_h/6,this.y-diglet_h,3,6);
            fill(255);
            ellipse(this.x-diglet_h/6,this.y-diglet_h-2,1,1);
            ellipse(this.x+diglet_h/6,this.y-diglet_h-2,1,1);
            //nose color
            fill(239,187,210);
            ellipse(this.x,this.y-diglet_h+6,diglet_h/3,5);
        }
    }
    //update whether the diglet appears
    this.update = function(){
        if (this.duration > 0){
            this.duration = this.duration - 0.5;
        }
        else {
            var temp_ratio = random(0,1);
            if (temp_ratio < 0.15){
                this.duration = random([1,2,3,4]);
            }
        }
    }
    //check if user clicked the diglet
    this.inDiglet = function(click_x,click_y){
        if (((click_x > this.x-diglet_h/2) & (click_x < this.x-diglet_h/2) && (click_y > this.y - diglet_h) && (click_y < this.y)) || (dist(click_x,click_y,this.x,this.y-diglet_h) < diglet_h)){
            if (this.duration > 0){
                this.duration = 0;
                num_hit += 1; 
            }   
        }
    }
}

//check  if when the mouse is pressed if it hits any diglet
function mousePressed() {
    for (var i = 0; i < num_diglets; i++){
        diglets[i].inDiglet(mouseX,mouseY);
    }
}

//when the game is over and you press r reset the game
function keyTyped(){
    if ((key === 'r') & (ended == 1)){
        ended = 0;
        time_elapsed = 0;
        ended = 0;
        num_hit = 0;
    }
}

amui1-Final-Project

amui1-final

//Allison Mui
//15-104 Section A
//amui1@andrew.cmu.edu
//Final Project

//variables for image
var monty = [];
var flyingMonty;
var swimmingMonty;
var evilOcty;
var bubble;
var bubbleX = [];
var bubbleY = [];
var punchMonty = [];
var monster;
var monstFall = [];
var homeMonty;

//variables for mouse movement
var targetX;
var targetY;

//variables for different states
var begin = true;
var home = false;
var world1 = false;
var world2 = false;
var world3 = false;
var over = false;

//variables for begin state
var playX;
var playY;

//variables for fire world1
var fires = [];
var fireCounter = 0;
var waterArray = [];

//variables for sea world
var octyY = 10;
var octySpeed = 4;
var inkSpeed;
var inkX = 280;
var inks = [];
var inkCounter = 0;

//variables for fight world
var fightmontyX = 130;
var fightmontyY = 350;
var fighttargetX = 130;
var fighttargetY = 350;
var monstX = 300;
var monstY = 280;
var monstSpeed = 5;
var level =  1;


//loads images
function preload() {
  //image for home monty
  homeMonty = loadImage("https://i.imgur.com/LudAnMM.png");
  //images for walking monty
  var montyfile = [];
  montyfile[0] = "https://i.imgur.com/jF4qiIL.png";
  montyfile[1] = "https://i.imgur.com/Q2Y2NMk.png";
  montyfile[2] = "https://i.imgur.com/Bhzuxet.png";
  montyfile[3] = "https://i.imgur.com/NXGRLMb.png";
  //loads monty
  for (var i = 0; i < 4; i++) {
    monty[i] = loadImage(montyfile[i]);
  }
  //image for fire world
  flyingMonty = loadImage("https://i.imgur.com/uogV1b7.png");
  //images for sea world
  bubble = loadImage("https://i.imgur.com/ZzkbRgi.png")
  swimmingMonty = loadImage("https://i.imgur.com/FwBvECT.png");
  evilOcty = loadImage("https://i.imgur.com/gYrnKp2.png");
  //images for fight world
  kickmonty = loadImage("https://i.imgur.com/ZpfaJlx.png")
  punchMonty[0] = loadImage("https://i.imgur.com/jF4qiIL.png");
  punchMonty[1] = loadImage("https://i.imgur.com/Q2Y2NMk.png");
  punchMonty[2] = loadImage("https://i.imgur.com/wCvUx2R.png");
  punchMonty[3] = loadImage("https://i.imgur.com/NXGRLMb.png");
  monster = loadImage("https://i.imgur.com/E0lKepM.png")
  monstFall[0] = loadImage("https://i.imgur.com/E0lKepM.png")
  monstFall[1] = loadImage("https://i.imgur.com/FX8hPMk.png");
}


function setup() {
    createCanvas(480,450);
    imageMode(CENTER);
    frameRate(4);
    // Initialize the character and target positions
    characterX = width/2;
    characterY = height/2;
    targetX = characterX;
    targetY = characterY;
    //fire world1
    dif = 0;
    for (var i = 0; i < 6; i++) {
        fires[i] = makeFire(width/4 + dif);
        dif += random(50,80);
    }
    //randomizing location for bubbles for sea world
    for (b = 0; b < 15; b++) {
      bubbleX.push(random(width));
      bubbleY.push(random(height));
    }
    //load bubble picture
    bubble.loadPixels();
    //loads home monty picture
    homeMonty.loadPixels();

}

function draw(){
    if (begin == true) {
      drawBegin();
    }
    if (home == true) {
      drawHome();
    }
    //calculates distance from monty to the world 1 icon
    var distWorld1 = dist(characterX,characterY,width/4,height/4);
    //if close enough, change the booleans to show a new screen
    if (distWorld1 < 10) {
      home = false;
      world1 = true;
      drawworld1();
    }
    //calulate distance from monty to world 2 icon
    var distWorld2 = dist(characterX,characterY,width/2+width/4,height/4);
    //if close enough, change booleans and show new screen
    if (distWorld2 < 10) {
      home = false;
      world2 = true;
      drawworld2();
    }
    //calculates distance from monty to world 3 icon
    var distWorld3 = dist(characterX,characterY,width/2,height/2+width/4+20);
    //if close enough, change booleans and show new screen
    if (distWorld3 < 10) {
      home = false;
      world3 = true;
      drawworld3();
    }
    //if too many points were lost (parameters in specific world), change screen
    if (over == true) {
      gameOver();
    }
}

function drawBegin() {
    background(0);
    image(homeMonty,width/2,height/2-20);
    textSize(24);
    fill(255);
    text("Lonnie's World",160,80);
    textSize(16);
    text("Lonnie travels from fire to sea, avoiding danger",80,110);
    textSize(20);
    text("Press play to begin", 160,350);
    var dPlay = dist(playX,playY,160,350);
    print(dPlay);
    if (dPlay < 80) {
      begin = false;
      home = true;
    }
}

function drawHome() {
    textSize(14);
    background(0);
    frameRate(4);
    //world 1
    strokeWeight(0);
    fill(229,115,115);
    ellipse(width/4,height/4,50,50);
    fill(240,171,171);
    ellipse(width/4,height/4,35,35);
    fill(255);
    text("Flames of Fury", width/4-40,height/4-35);
    //world 2
    fill(109,181,255);
    ellipse(width/2+width/4,height/4,50,50);
    fill(167,211,255);
    ellipse(width/2+width/4,height/4,35,35);
    fill(255);
    text("Waves of Fear", width/2+width/4-35,height/4-35);
    //fight world
    fill(255,253,41);
    ellipse(width/2,height/2+width/4+20,50,50);
    fill(255,254,127);
    ellipse(width/2,height/2+width/4+20,35,35);
    fill(255);
    text("Fight Club",width/2-25,height/2+width/4-15);
    //move monty according to where user clicks
    var dx = targetX - characterX;
    var dy = targetY - characterY;
    //cycles through all image files to walk
    image(monty[frameCount%4], characterX, characterY);
    characterX = characterX + dx/10;
    characterY = characterY + dy/10;
}

function mousePressed() {
    //sets new target for play button
    playX = mouseX;
    playY = mouseY;
    //set boundaries for user's mouse
    targetX = mouseX;
    targetY = mouseY;
    targetX = constrain(mouseX,0,width-50);
    targetY = constrain(mouseY,0,height-50);
    //sets new target for the fight world
    fighttargetX = mouseX;
    fighttargetY = mouseY;
}

function drawworld1() {
    background(0);
    frameRate(12);
    //sets the monster's position
    var flyingmontyX = mouseX;
    var flyingmontyY = mouseY;
    //constrains the monsters position to not move past the middle and canvase
    var flyingmontyY = constrain(flyingmontyY,40,height-90);
    var flyingmontyX = constrain(flyingmontyX,45,height/2);
    //displays image
    image(flyingMonty,flyingmontyX,flyingmontyY);
    strokeWeight(0);
    //displays fire
    showFire();
    //instructions
    noFill();
    stroke(255);
    strokeWeight(1);
    rect(0,height-50,width,50);
    strokeWeight(0);
    fill(255);
    text("Avoid the fire or you'll get burned!", 10,height-28);
    text("Points: " + fireCounter, width-70,height-30);
    //if mouse over "go home" returns to the home screen
    text("Go Home", width-70, height-10);
    var distHome = dist(mouseX,mouseY,width-70,height-10);
    if (distHome < 15) {
      home = true;
    }
    //ends game if points too low
    if (fireCounter < -100) {
      over = true;
    }
}

function drawworld2() {
    frameRate(15);
    background(175,246,249);
    //draw bubbles
    for (bub = 0; bub < 15; bub++) {
      image(bubble,bubbleX[bub],bubbleY[bub]);
    }
    //changes speed by a random amount(speedif) as time goes on
    if (frameCount % 60 == 0) {
      speeddif = random(1,3);
      octySpeed = octySpeed + speeddif;
    }
    //make new ink blots at different times
    if (frameCount % 60 == 0) {
      inks.push(makeInk(inkX,octyY));
    }
    //displays ink
    showInk();
    //monty moves with mouse
    swimX = mouseX;
    swimY = mouseY;
    //sets boundaries so monty doesn't go off the page
    var swimY = constrain(swimY,30,height-90);
    var swimX = constrain(swimX,0,width/4);
    //display monty
    image(swimmingMonty,swimX,swimY);
    //displays the octopus monster
    image(evilOcty,width-120,octyY);
    //moves octy
    octyY += octySpeed;
    //sets actions so octy doesn't move off the page
    if (octyY > height-90) {
      octySpeed = -octySpeed;
    }
    if (octyY < 10) {
      octySpeed = -octySpeed;
    }
    //instructions
    rectMode(CORNER);
    fill(40,40,57);
    stroke(255);
    strokeWeight(1);
    rect(0,height-50,width,50);
    strokeWeight(0);
    fill(255);
    text("The evil octopus is squirting ink!", 10,height-28);
    text("Avoid the head of the ink!", 10, height-10);
    text("Points: " + inkCounter, width-70,height-30);
    text("Go Home", width-70, height-10);
    //calculates where mouse is, if over home button, draw home state
    var distHome = dist(mouseX,mouseY,width-65,height-10);
    if (distHome < 15) {
      home = true;
    }
    //only go through this only if inks array is populated
    //add points if monster successfully avoids the ink
    if (inks.length > 0) {
      //if monster hits the ink, deduct 5 points
      if ((swimX > inks[0].x-100 & swimX < inks[0].x+100) &&
          (swimY > inks[0].y-5 && swimY < inks[0].y+30)) {
        inkCounter -= 1;
      }
      //remove ink blots after it moves off the page
      if (inks[0].x < 0) {
        inkCounter += 1;
        inks.shift(1);
      }
    }
    //end game if too many points lost
    if (inkCounter < -100) {
      over = true;
    }
}

function drawworld3() {
    background(47,100,145);
    //draw boxing design
    drawBoxingRing();
    //calculates distance between monster fighting and monty
    var dFight = dist(fightmontyX,fightmontyY,monstX,monstY);
    //if monty runs into monster, then game is over
    if (dFight < 90) {
      over = true;
    }
    //fight monster
    //punches monster if monty is close enough
    if(dFight < 98 & keyIsDown(80)) {
      //if monster is punched, monster "falls down"
      //cycles through image array
      image(monstFall[frameCount%2],monstX,monstY);
    }
    //if monster is not punched, move monster from right to left
    else {
      image(monster,monstX,monstY);
      monstX -= monstSpeed;
      //sets boundary for the monster
      if (monstX < 150) {
        monstSpeed = -monstSpeed;
      }
      if (monstX > 300) {
        monstSpeed = -monstSpeed;
      }
    }
    //image of the fighting monty
    //calculates distance for movement of monty
    var dx = fighttargetX - fightmontyX;
    var dy = fighttargetY - fightmontyY;
    //constrains the boundary of monty
    fightmontyX = constrain(fightmontyX,30,300);
    fightmontyY = constrain(fightmontyY,height-150,height-80);
    //moves monty
    fightmontyX = fightmontyX + dx/10;
    fightmontyY = fightmontyY + dy/10;
    //if user doesn't call monty to move, monty is still
    if (fightmontyX == fighttargetX & fightmontyY == fighttargetY) {
      image(monty[0], fightmontyX, fightmontyY);
    }
    //if monty is punching, restrict image so punch monty will match
    if (keyIsDown(80) & (frameCount%4 == 0 || (frameCount%4 == 2))) {
      image(punchMonty[2],fightmontyX,fightmontyY);
    }
    //if user calls monty to move, monty moves and cycles through all image files
    if (fightmontyX != fighttargetX || fightmontyY != fighttargetY) {
      image(monty[frameCount%4],fightmontyX,fightmontyY);
    }
    //instructions
    fill(35,75,109);
    stroke(255);
    strokeWeight(1);
    rect(0,height-50,width,50);
    strokeWeight(0);
    fill(255);
    textSize(13);
    text("Battle the hungry bear!", 10,height-28);
    text("Click to move and hold 'p' to punch!", 10, height-10);
    text("Level: " + level, width-70,height-30);
    text("Go Home", width-70, height-10);
    //calculates distance from user's mouse to the go home button
    var distHome = dist(mouseX,mouseY,width-65,height-10);
    //if user's mouse is on the go home button, draw home state
    if (distHome < 15) {
      home = true;
    }
    //increases level after some time passed
    if (frameCount%2000 == 0) {
      level += 1;
    }
}

function drawBoxingRing() {
    //background design to make look like boxing setting
    strokeWeight(0);
    fill(35,79,109);
    rect(0,height-120,width,100);
    stroke(35,79,109);
    strokeWeight(15);
    line(10,height-50,width/4-20,130);
    line(250,height-50,width/2+80,130);
    line(250,height-50,width/4+30,130);
    line(480,height-50,380,130);
    strokeWeight(0);
    fill(35,75,109);
    rect(0,0,width,130);
    //lights
    stroke(255);
    strokeWeight(5);
    line(150,145,160,145);
    line(155,140,155,150);
    line(300,170,310,170);
    line(305,165,305,175);
    //banner
    fill(189,57,51);
    strokeWeight(5);
    rect(width-180,30,140,40);
    strokeWeight(0);
    fill(255);
    textSize(15);
    text("Fight! Train! Win!",width-165,55);
    //boxing ring
    fill(255);
    strokeWeight(0);
    triangle(20,height-50,100,height-160,100,height-50);
    rect(100,height-160,280,150);
    triangle(380,height-50,380,height-160,460,height-50);
    fill(189,57,51);
    triangle(30,height-50,100,height-150,100,height-50);
    rect(100,height-150,280,150);
    triangle(380,height-50,380,height-150,450,height-50);
    //boxing horizontal lines - "strings around the ring"
    stroke(255);
    strokeWeight(3);
    //left
    line(30,height-140,125,height-248);
    line(30,height-120,125,height-230);
    line(30,height-100,125,height-210);
    //mid
    line(125,height-230,360,height-230);
    line(125,height-210,360,height-210);
    line(125,height-190,360,height-190);
    //right
    line(360,height-248,450,height-140);
    line(360,height-230,450,height-120);
    line(360,height-210,450,height-100);
    //boxing columns
    fill(142,43,38);
    strokeWeight(0);
    rect(20,height-200,40,200,5);
    rect(100,height-250,40,100,5);
    rect(340,height-250,40,100,5);
    rect(height-30,height-200,40,200,5);
}

function gameOver() {
    background(0);
    textSize(50);
    text("Game Over",15,height/2);
    textSize(14);
    text("Please refresh to start over :)",20,height/2+50);
}

function showInk() {
    //moves and draws inks in the ink array
    for (var i = 0; i < inks.length; i++) {
      inks[i].draw();
      inks[i].move();
    }
}

function moveInk() {
    this.x -= this.speed;
}

function drawInk() {
    //draw ink
    strokeWeight(0);
    fill(40,40,57);
    rectMode(CENTER);
    rect(this.x,this.y,200,20,10);
    rect(this.x,this.y+25,180,20,10);
}

function makeInk(x,y) {
    m = {x:x,
         y:y,
         speed: random(5,8),
         draw: drawInk,
         move: moveInk}
    return m;
}

function showFire() {
    //go through fire Array
    for (var fiyah = 0; fiyah < fires.length; fiyah++) {
      //alternate fire design
      //if even number, show fire coming from the bottom of the canvas
      if (fiyah % 2 == 0) {
        fires[fiyah].drawup();
        fires[fiyah].move();
      }
      //if odd number, show fire coming from the top
      if (fiyah % 2 != 0) {
        fires[fiyah].drawdown();
        fires[fiyah].move();
      }
    }
}

function moveFire() {
    //sets the monster's position
    var flyingmontyX = mouseX;
    var flyingmontyY = mouseY;
    //constrains the monsters position to not move past the middle and canvase
    var flyingmontyY = constrain(flyingmontyY,40,height-90);
    var flyingmontyX = constrain(flyingmontyX,45,height/2);
    //moves fire
    this.x -= this.speed;
    //if fire moves off page, points go up
    if (this.x < 0-30) {
      this.x = width;
      fireCounter += 1;
    }
    //calculates distance from monty to fire
    if (flyingmontyY < height/2) {
      var dFire = dist(flyingmontyX,flyingmontyY,this.x,this.h);
    }
    if (flyingmontyY > height/2) {
      var dFire = dist(flyingmontyX,flyingmontyY,this.x,height-this.h);
    }
    //if monty too close to fire, deduct points
    if (dFire < 20) {
      fireCounter -= 5;
    }
}

//if fire is coming from the floor
function drawupFire(){
    //draws redish flame
    fill(216,82,42);
    triangle(this.x-20,height-50,this.x-5-random(1,10),height-50-(this.h+60)-random(1,50),
              this.x+50+random(1,10),height-50);
    triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+60)-random(1,60),
              this.x+50+random(1,10),height-50);
    triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+60)-random(1,50),
              this.x+55+random(1,10),height-50);
    //draws orange flame
    fill(221,144,44);
    triangle(this.x-15,height-50,this.x-5-random(1,10),height-50-(this.h+40)-random(1,40),
              this.x+40+random(1,10),height-50);
    triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+40)-random(1,50),
              this.x+40+random(1,10),height-50);
    triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+40)-random(1,40),
              this.x+45+random(1,10),height-50);
    //draws dark yellow flame
    fill(233,219,47);
    triangle(this.x-10,height-50,this.x-5-random(1,10),height-50-(this.h+20)-random(1,30),
              this.x+30+random(1,10),height-50);
    triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+20)-random(1,40),
              this.x+30+random(1,10),height-50);
    triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+20)-random(1,30),
              this.x+35+random(1,10),height-50);
    //draws light yellow frame
    fill(255,250,163);
    triangle(this.x-5,height-50,this.x-5-random(1,10),height-50-this.h-random(1,20),
              this.x+20+random(1,10),height-50);
    triangle(this.x,height-50,this.x+10+random(-1,5),height-50-this.h-random(1,30),
              this.x+20+random(1,10),height-50);
    triangle(this.x,height-50,this.x+20+random(1,10),height-50-this.h-random(1,20),
              this.x+25+random(1,10),height-50);
}

//if fire coming from ceiling
function drawdownFire(){
    //draws redish flame
    fill(216,82,42);
    triangle(this.x-20,0,this.x-5-random(1,10),0+(this.h+60)-random(1,50),
              this.x+50+random(1,10),0);
    triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+60)-random(1,60),
              this.x+50+random(1,10),0);
    triangle(this.x,0,this.x+20+random(1,10),0+(this.h+60)-random(1,50),
              this.x+55+random(1,10),0);
    //draws orange flame
    fill(221,144,44);
    triangle(this.x-15,0,this.x-5-random(1,10),0+(this.h+40)-random(1,40),
              this.x+40+random(1,10),0);
    triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+40)-random(1,50),
              this.x+40+random(1,10),0);
    triangle(this.x,0,this.x+20+random(1,10),0+(this.h+40)-random(1,40),
              this.x+45+random(1,10),0);
    //draws dark yellow flame
    fill(233,219,47);
    triangle(this.x-10,0,this.x-5-random(1,10),0+(this.h+20)-random(1,30),
              this.x+30+random(1,10),0);
    triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+20)-random(1,40),
              this.x+30+random(1,10),0);
    triangle(this.x,0,this.x+20+random(1,10),0+(this.h+20)-random(1,30),
              this.x+35+random(1,10),0);
    //draws light yellow frame
    fill(255,250,163);
    triangle(this.x-5,0,this.x-5-random(1,10),0+this.h-random(1,20),
              this.x+20+random(1,10),0);
    triangle(this.x,0,this.x+10+random(-1,5),0+this.h-random(1,30),
              this.x+20+random(1,10),0);
    triangle(this.x,0,this.x+20+random(1,10),0+this.h-random(1,20),
              this.x+25+random(1,10),0);
}

function makeFire(x){
    f = {x:x,
         h: random(20,130),
         speed: random(1,8),
         drawup: drawupFire,
         drawdown: drawdownFire,
         move: moveFire}

    return f;
}

Features

  • Click to move or “hit” buttons such as play or go home
  • In different worlds, character moves along with the user’s mouse movements to avoid obstacles.
  • In the fight world, user can click p for added interaction.

Reflection

I enjoyed this project a lot because it was so challenging, but fun and rewarding. I really felt like I put what I learned in this class to test. Trying to incorporate something I learned from each week, I saw the vast power creative computing has. The most enjoyable part was seeing how far this project has come: from storyboard to now. The most challenging part was trying to fix, adjust, and adapt my game when a programming difficulty came up (which was often). In addition, I had a lot of fun creating the visuals in this project and then adding motion to them. All in all, I am happy with my project’s final outcome.

Caption: Above is my first storyboard of my game. As you can see, my idea has changed quite a bit from beginning to end. However, my main concept of moving a character through different worlds or states remained the same.

Caption: Above are the 3 worlds my character travels through.