Week 6: Midterm Project (Sounds Like NYUAD)

Remind me to never create a sound-based game again.

This project was a roller coaster, there were some days where I would take the entire day just to debug one tiny thing, and some days where I could make a huge advancement with little resistance. Thankfully, I am happy to where I got.

Trying to make sense/ organzie/ my old code

Since I already had a python based code, starting the game was easy. Myfirst few elements, the image, the map, the player were easy to achieve, but it changed fast. When I got to the borders, I had to redo a large aspect of what it used to be. I refined them, which was time-consuming because of how I had to keep track of X and Y values of the borders since I individually drew them. Then figuring out the movement of the player in relation to the borders was a nightmare. It was nothing related to my previous code, and after spending the whole day on it, I resorted to pencil and paper, trying to figure out how to code the movement. Here’s my sad sketch:

After that celebratory dance, I was on to other elements, like the cats. This proved to be relatively easy, since I had coded this kind of thing before. You hit a cat, you die. It was simple. It was so easy, as a matter of fact, I thought it would be great if I would add another element, humans. I thought “they’re so simple, and I could just make it so that if I hit them, I lose points and time, I don’t die.” After spending a few hours sketching 5 illustrations of humans, and adding it to my code, I realised I had misjudged how ‘easy’ it was. My issue was that I had my code so that whenthe distance between the player and the object is less than an amount, the score decreases. The issue with this is that it would continuously decrease until the object is out of bounds when I just wanted it to decrease once. Eventually, I did it in a way where once it hits the object, a boolean is triggered to true, you lose the points, and then after 1 second, the boolean goes back to false, and you can hit it again. (you probably shouldn’t though).

Other elements I was excited to add were things like adding a score, where it was calculated based on your time (the faster the better) and each sound you find, and it tells you your score at the end. (A very small thing I added was changing the score to green when it’s positive, red when it’s negative). Another thing was also adding a tally on the top left of the screen, to see how many sounds left to find, as playing it I realized I was always wondering how many I had left.

Another element I added (although it doesn’t look as nice as I wanted it to), was having the location you are at glow in gold for a second to indicate that you found the sound in that spot. I also made a ‘ding’ sound to be heard when you get a point, so that you know it happened. I changed the main players’ face to my off-brand illustration of the NYUAD falcon, which I’m not a fan of, but someone pointed out to me that with the addition of humans, the player cannot be sure which one they are controlling.

The sound was tricky, because there were so many bugs that kept showing up. Java only allows sound in the main program, not in classes, so I had to keep experimenting and trying to see how to fix these issues. For example, having the sounds in an array didn’t work. Often times the sounds would overlap because of the draw loop triggered over and over again, especially when mixed with restarting, the sounds would layer over each other. My main solution was to make sure that when the game runs, all the sounds are playing but on mute, so when a location is triggered, the sound unmutes, instead of just playing at a random tempo. Also made sure for the song to keep playing when you win, so you can hear your music, but to stop playing when you die.

Moving on to the restart, instruction, and game over screens. These where also a struggle to figure out, because instead of having most of my initiations in a class like I would normally do, I had it in the main page to correlate with the sounds. Eventually, I figured it out, having functions for each screen, and then debugging for a while. I also had to redesign a few elements for the screens.

int gameScreen = 0;
PImage dead, won, instructions;
boolean trigger = false;
Game game;
Creature creature;
Cats[] cats;
Humans[] humans;
Borders[] horizentalBorders;
Borders[] verticalBorders;
Locations[] locations;
//SoundFile[] sounds;
SoundFile backgroundSound, meow, ding, baraha, alarm, dining, library, knock, palms, theatre;

void setup() {
  //This trigger is just fir the cat meow
  trigger = false;
  creature = new Creature (50, 450, 10);
  game = new Game (1024, 786, 585);
  cats = new Cats[3];
  humans = new Humans[3];
  //for displaying the cats and humans, in random places and speeds
  for ( int g = 0; g< 3; g++) {
    cats[g] = new Cats (int(random(200, 900)), int(random(200, 600)), 15, 70, 70, 200, 800);
    humans[g] = new Humans (int(random(200, 900)), int(random(200, 900)), 15, 70, 70, 200, 800);
  }
  //Creating the locations for the sound to br triggered. These dont change
  locations = new Locations[7];
  locations[0] = new Locations (250, 270, 100); // library
  locations[1] = new Locations ( 250, 470, 100); // Palms
  locations[2] = new Locations (400, 310, 50); //baraha
  locations[3] = new Locations (790, 250, 100); //theatre
  locations[4] = new Locations (950, 400, 100); //dining
  locations[5] = new Locations (800, 620, 200); // knock
  locations[6] = new Locations (570, 570, 200); // alarm
  size(1024, 768);
  background(255, 255, 255);
  //borders of the map, where you cannot enter from
  horizentalBorders = new Borders[14];
  verticalBorders = new Borders[13];
  horizentalBorders[1] = new Borders (444, 286, 575, 286); //h
  horizentalBorders[2] = new Borders (442, 346, 520, 346); //h 
  horizentalBorders[3] = new Borders (402, 470, 502, 470); //h
  horizentalBorders[4] = new Borders (590, 472, 712, 472); //h
  horizentalBorders[5] = new Borders (754, 493, 812, 493); //h
  horizentalBorders[6] = new Borders (70, 175, 440, 175); // h
  horizentalBorders[7] = new Borders (70, 375, 422, 375); //h
  horizentalBorders[8] = new Borders (310, 725, 970, 725); //h
  horizentalBorders[9] = new Borders (530, 527, 586, 527); //h 
  horizentalBorders[10] = new Borders (536, 595, 586, 595); // h
  horizentalBorders[11] = new Borders (350, 614, 396, 614); //h
  horizentalBorders[12] = new Borders (754, 602, 808, 602); // h
  horizentalBorders[0] = new Borders (756, 640, 808, 640); // h
  verticalBorders[12] = new Borders (440, 175, 440, 270); //h
  verticalBorders[1] = new Borders (540, 346, 540, 455); //v
  verticalBorders[2] = new Borders (582, 286, 582, 456);// v
  verticalBorders[3] = new Borders (70, 175, 70, 375); //v
  verticalBorders[4] = new Borders (310, 572, 310, 725); //v
  verticalBorders[5] = new Borders (970, 525, 970, 725);  // v
  verticalBorders[6] = new Borders (775, 675, 775, 720); // v
  verticalBorders[7] = new Borders (800, 675, 800, 720); //v 
  verticalBorders[8] = new Borders (586, 527, 586, 595); // v
  verticalBorders[9] = new Borders (536, 529, 536, 595); //v
  verticalBorders[10] = new Borders (396, 614, 396, 664); //v
  verticalBorders[11] = new Borders (808, 602, 808, 640); // v
  verticalBorders[0] = new Borders (756, 602, 756, 640); // v
  //if you die- page
  dead = loadImage("sorry.png");
  //if you win - page
  won = loadImage("finalpage.png");
  //instructional page
  instructions = loadImage("instructions.png");
  //loading the sounds of the song
  backgroundSound = new SoundFile(this, "OriginalBacktrack.mp3");
  baraha = new SoundFile(this, "CardSwipe.mp3");
  knock= new SoundFile(this, "Knock_RA.mp3");
  theatre = new SoundFile(this, "SneezeCough.mp3");
  library = new SoundFile(this, "Typing_clicking.mp3"); 
  palms = new SoundFile(this, "Birds.mp3");
  dining = new SoundFile(this, "Didyoudothereading.mp3");   
  alarm = new SoundFile(this, "iPhoneAlarm.mp3"); 
  meow = new SoundFile(this, "meow.mp3");
  ding = new SoundFile(this, "Ding.mp3");

//playing all the sounds in loop for easier restart (less bugs), all on mute except background, 
// this is so that whenever they are triggered they are still on tempo for the song
  backgroundSound.play();
  baraha.loop();
  baraha.amp(0.0);
  knock.loop();
  knock.amp(0.0);
  theatre.loop();
  theatre.amp(0.0);
  library.loop();
  library.amp(0.0);
  dining.loop();
  dining.amp(0.0);
  alarm.loop();
  alarm.amp(0.0);
  meow.amp(0.5);
  //restart();
}

void sound() {
  // locating each location for their respective sound, because an array of sounds did not work
  if ( locations[0].trigger == true) {
    library.amp(1.0);
    println("library");
  }
  if ( locations[1].trigger == true) {
    palms.amp(1.0);
  }
  if ( locations[2].trigger == true) {
    baraha.amp(1.0);
  }
  if ( locations[3].trigger == true) {
    theatre.amp(1.0);
  }
  if ( locations[4].trigger == true) {
    dining.amp(1.0);
  }
  if ( locations[5].trigger == true) {
    knock.amp(1.0);
  }
  if ( locations[6].trigger == true) {
    alarm.amp(1.0);
  }
}

void initScreen() {
  //initial screen, instruction page
  image(instructions, 0, 0);
  text("Click anywhere to begin ! ", 300, 700);
}

void restart() {
  // upon restart
  // this was a response to a cat bug
  trigger = false;
  creature = new Creature (50, 450, 10);
  game = new Game (1024, 786, 585);
  cats = new Cats[3];
  humans = new Humans[3];
  for ( int g = 0; g< 3; g++) {
    cats[g] = new Cats (int(random(200, 900)), int(random(200, 600)), 15, 70, 70, 200, 800);
    humans[g] = new Humans (int(random(200, 900)), int(random(200, 900)), 15, 70, 70, 200, 900);
  }
  locations = new Locations[7];
  locations[0] = new Locations (250, 270, 100); // library
  locations[1] = new Locations ( 250, 470, 100); // Palms
  locations[2] = new Locations (400, 310, 50); //baraha
  locations[3] = new Locations (790, 250, 100); //theatre
  locations[4] = new Locations (950, 400, 100); //dining
  locations[5] = new Locations (800, 620, 200); // knock
  locations[6] = new Locations (570, 570, 200); // alarm

  backgroundSound.loop();
  baraha.loop();
  baraha.amp(0.0);
  knock.loop();
  knock.amp(0.0);
  theatre.loop();
  theatre.amp(0.0);
  library.loop();
  library.amp(0.0);
  dining.loop();
  dining.amp(0.0);
  alarm.loop();
  alarm.amp(0.0);
  //meow.loop();
  meow.amp(0.5);
}

void draw () {
  // to make it easier which game scteen we are on
  if (gameScreen == 0) {
    // instructions page
    initScreen();
  } else if (gameScreen == 1) {
    // the game
    gameScreen();
  } else if (gameScreen == 2) {
    // if you lose
    gameOverScreen();
  } else if (gameScreen == 3) {
    // if you win
    gameWinScreen();
  }
}

void gameScreen() {
  game.display();
  creature.display();
  for ( int g = 0; g< 3; g++) {
    cats[g].display();
    humans[g].display();
  }
  for ( int n = 0; n < 12; n ++) {
    horizentalBorders[n].displayBorders();
  }
  for ( int m = 0; m < 13; m ++) {
    verticalBorders[m].displayBorders();
  }
  for ( int l = 0; l <7; l ++) {
    // checking if the locations are triggered
    locations[l].display();
    locations[l].trigger();
  }
  if (game.count <= 0) {
    // if the time runs our, you lose
    creature.alive = false; 
    creature.win = false;
  }
  if (creature. alive == false && creature.win == true) {
    // if you win
    gameScreen=3 ;
    gameWinScreen();
  }
  if (creature. alive == false && creature.win == false) {
    // if you lose
    gameScreen=2 ;
    gameOverScreen();
  }
}

void gameOverScreen() {
  // lost screen
  image (dead, 187, 59);
}
void gameWinScreen() {
  // won screen, dsplaying score as well
  image (won, 187, 59);
  text("Your Score: " + int(game.scorecount), 420, 420);
}

void mouseClicked() {
  if ( gameScreen == 0) {
    gameScreen= 1;
  }
  if (gameScreen == 2 || gameScreen == 3) {
    restart();
    gameScreen= 1;
    println("restart");
  }
}
// class borders for the map 
class Borders{
  float x, y, x2, y2;
  
  Borders (int _x, int _y, int _x2, int _y2 ){
    x = _x;
    y = _y;
    x2 = _x2;
    y2 = _y2;
    
  
  }
  
  void displayBorders(){
  //stroke(200);
  noStroke();
  line(x,y,x2,y2);
  }
}
// creature cats

class Cats {
  float x, y, r, w, h, x1, x2;
  float vy = 0;
  float vx = 0;
  boolean alive = true;
  PImage img; 

  Cats (float _x, float _y, int _r, int _w, int _h, int _x1, int  _x2) {
    x = _x;
    y = _y;
    r = _r;
    vy = 0;
    vx = random(1, 3);
    w = _w;
    h = _h;
    x1 = _x1;
    x2 = _x2;   
    // picking a random image of the 3 cat versions
    img = loadImage("cat" + str(int(random(1, 4))) + ".png");
  }

  void display() {
    update();
    noFill();
    noStroke();
    image( img, x-r, y-r, 50, 50);
    circle(x, y, r*2);
  }

  void update() {
  // movement of the cats 
    y += vy;
    x += vx; 
    
    // for the cats to move back and forth
    if (x < x1) {
      vx *= -1;
    } else if ( x > x2) {
      vx *= -1;
    }
  }

  float distance(int tarX, int tarY) {
    // to calculate the distance between the cat and another object
    return (pow( (pow(( x - tarX), 2) + pow((y - tarY), 2)), 0.5));
  }

  boolean trigger() {
    return false;
  }
}
//Clas for player 
class Creature {
  int x, y, r;
  float vy = 0;
  float vx = 0;
  int directionH = 0; 
  int numloc = 0;
  boolean alive = true;
  boolean win = false;
  boolean borderCheckY = true;
  boolean borderCheckX = true;
  PImage img, green;
  boolean leftKey = false;
  boolean rightKey = false;
  boolean upKey = false;
  boolean downKey = false;
  int previousTime = 0;
  float timePassed = 1000;


  Creature (int _x, int _y, int _r) {
    x = _x;
    y = _y;
    r = _r;
    vy = 0;
    vx = 0;
    img = loadImage("player.png");
  }

  void sound() {
    // function to equate each sound to its respective location, play the sound upon trigger
    if ( locations[0].trigger == true) {
      library.amp(1.0);
    }
    if ( locations[1].trigger == true) {
      palms.amp(1.0);
    }
    if ( locations[2].trigger == true) {
      baraha.amp(1.0);
    }
    if ( locations[3].trigger == true) {
      theatre.amp(1.0);
    }
    if ( locations[4].trigger == true) {
      dining.amp(1.0);
    }
    if ( locations[5].trigger == true) {
      knock.amp(1.0);
    }
    if ( locations[6].trigger == true) {
      alarm.amp(1.0);
    }
  }

  void display() {
    update();
    noFill();
    noStroke();
    image( img, x-r, y-r, 50, 50);
    circle(x, y, r*2);
  }

  void update() {
    keyPressed();

    y += vy;
    x += vx;

    // for movement of the player and keys + game borders
    if ( leftKey == true && x>=0) {
      directionH = 1;
      vx = -1;
    } else if ( rightKey == true && x + r <= 1024) {
      vx = 1;
      directionH = 0;
    } else if ( downKey == true && y +r <= 784) {
      vy = 1;
    } else if ( upKey == true && y >= 0  ) {
      vy = -1;
    } else { 
      vx = 0;
      vy = 0;
    }

    // checking for collision of map borders
    collisionY();
    collisionX();

    for ( int g = 0; g< 3; g++) {
      if (cats[g].distance(x, y) <= r +cats[g].r ) {
        // when player hits a cat
        if (trigger == false) {
          // mouse sound effect + you die, and the sounds stop
          meow.play();
          palms.amp(0.0);
          baraha.amp(0.0);
          library.amp(0.0);
          theatre.amp(0.0);
          dining.amp(0.0);
          knock.amp(0.0);
          alarm.amp(0.0);
          println("meow");
          trigger = true;
          alive = false;
          win = false;
        }
      }
      // if you hit a human, your score goes down, and you lose 10 seconds off your timer
      if (humans[g].distance(x, y) <= r +humans[g].r) {
        if (humans[g].trigger == false) {
          game.count -=10;
          game.scorecount-=20;
          previousTime = millis();
          humans[g].trigger = true;
          game.display();
        }
        if ( millis() > previousTime + timePassed) {
          previousTime= millis();
          humans[g].trigger = false;
        }
      }
    }

    // probably one of the most important parts. Code to see if you hit a location
    for ( int o = 0; o< 7; o++) {
      if (locations[o].trigger == false) {
        if (locations[o].distance(x, y) <= 20) {
          locations[o].trigger = true; 
          if (tally.size() >0) {
            // adds to your score
            numloc +=1;
            game.scorecount += ((120 - (millis()/1000))*creature.numloc);
            println(game.scorecount);
            // removes a string on top left to see how many you have left
            tally.remove(0);
            locations[o].display2();
            // ding as an indicator that you got one
            ding.play();
            sound();
            //image (green, height, width);
            println(tally);
          }
        }
        // check for a win. If the string length == 0, you won
      } else if (tally.size() == 0) {
        win = true;
        alive = false;
      }
    }
  }
  // checking to see if you hit the horizontal borders. makes you stop moving
  void collisionY() {
    for (int i = 0; i <13; i++ ) {
      if ( vy + y + r >= horizentalBorders[i].y && 
        vx + x + r >= horizentalBorders[i].x &&
        x + vx +r <= horizentalBorders[i].x2 && 
        vy + y + r <= horizentalBorders[i].y2) {
        vy = 0;
      }
    }
  }
  // collision with vertical borders.
  void collisionX() {
    for (int j = 0; j < 11; j++) {
      if ( vx + x + (r*2) <= verticalBorders[j].x && 
        vx + x + (r*2) >= verticalBorders[j].x2 &&
        y + vy + r >= verticalBorders[j].y && 
        vy + y + r <= verticalBorders[j].y2) {
        //println("stop3");
        vx = 0;
      }
    }
  }

  // equating key pressed with players movements
  void keyPressed() {
    if (keyPressed && keyCode == LEFT ) {
      leftKey = true;
    } else {
      leftKey = false;
    }
    if (keyPressed && keyCode == RIGHT) { //&& x+r <= game.w
      rightKey = true;
    } else {
      rightKey = false;
    }
    if (keyPressed && keyCode == UP) {
      upKey = true;
    } else {
      upKey = false;
    }
    if (keyPressed && keyCode == DOWN) { // && y+r <= game.h
      downKey = true;
    } else {
      downKey = false;
    }
  }



  float distanceCreature(int tarX, int tarY) {
    return (pow( (pow(( x - tarX), 2) + pow((y - tarY), 2)), 0.5));
  }
}
import processing.sound.*;
PImage img;
StringList tally;

class Game {
  float w, h, g;
  int count = 120;
  float scorecount = 0;

  Game(int _w, int _h, int _g) {
    w = _w;
    h = _h;
    g = _g;
    img = loadImage("map.jpg");
    tally = new StringList("I", "I", "I", "I", "I", "I", "I" );
  }

  void display () {
    // map image
    image (img, 0, 0);
    fill (0, 0, 0);
    textSize(25);
    // 3d effect on timer
    text("Time Remaining: " + count, 365, 50);
    fill(255, 255, 255);
    textSize(25);
    text("Time Remaining: " + count, 363, 48 );
    fill (255, 255, 255);
    // displaying the tally on the left
    for (int i = 0; i <tally.size(); i++) {
      text (tally.get(i), 50+(i*10), 50);
    }
    fill(150, 17, 17);
    for (int i = 0; i <tally.size(); i++) {
      text (tally.get(i), 50+(i*10), 50);
    }
    fill (255, 255, 255);
    text ("Score: " + int(scorecount), 850, 50);
    // displaying score, with 3d effect and also green if positive, red if negative
    if (scorecount <=0) {
      fill(150, 17, 17);
      text ("Score: " + int(scorecount), 849, 49);
    } else if (scorecount >=0) {
      fill(17, 150, 17);
      text ("Score: " + int(scorecount), 849, 49);
    }

    // for decreasing time
    if (creature.alive == true) {
      if (frameCount % 60 == 0) {
        //println (frameCount);
        count   -=1;
      }
      if (count <= 0) {
        creature.win=false;
        creature.alive = false;
      }
    }
  }
}
// creature cats

class Humans {
  float x, y, r, w, h, y1, y2;
  float vy = 0;
  float vx = 0;
  boolean alive = true;
  PImage img; 
  boolean trigger = false;

  Humans (float _x, float _y, int _r, int _w, int _h, int _y1, int  _y2) {
    x = _x;
    y = _y;
    r = _r;
    vx = 0;
    vy = random(1, 3);
    w = _w;
    h = _h;
    y1 = _y1;
    y2 = _y2;   
    img = loadImage("human" + str(int(random(1, 6))) + ".png");
  }

  void display() {
    update();
    noFill();
    noStroke();
    image( img, x-r, y-r, 50, 50);
    circle(x, y, r*2);
  }

  void update() {

    y += vy;
    x += vx; 

    if (y < y1) {
      vy *= -1;
    } else if ( y > y2) {
      vy *= -1;
    }
  }

  float distance(int tarX, int tarY) {
    return (pow( (pow(( x - tarX), 2) + pow((y - tarY), 2)), 0.5));
  }

  boolean trigger() {
    return false;
  }
}

 

Zip:IntroMidtermProject

Finally, here is the final game (That i am very bad at playing, sorry its so frustrating to watch):

Leave a Reply