Week 7: Midterm Project Sorting Game

Description:

This project consisted of creating a game for our midterm assignment. The game had to include several elements such as shapes, images, sound, text, an initial screen with instructions, and a way to restart the game when the game is lost or won.

Process:

Idea:

I had several ideas when I first started thinking about this assignment. One of my initial ideas was to work on the game I had been working on before in Week 3. The game consisted of a car trying to avoid obstacles by using the left and right arrow keys. However, I wanted to challenge myself and create a game from scratch. First, I thought about recreating an old retro game. Then I changed my mind to create a “Whack a Mole” game. Finally, I remembered a game I used to play when I was a child. This game was a mini-game from Mario Bros on the Nintendo called “Sort or Splode”. The game consisted of sorting different colored bombs into their own color platforms. If a bomb was not sorted on time it would explode and the game would be over. If a bomb was placed on the wrong platform, the game woul

 

d also be over. Since I was recreating a game, I decided to include the creativity part in the visual part of the game. I decided to create my own background and characters and base them on an NYU theme. The idea was to sort falcons and bobcats into different platforms that represent NYU and NYUAD. 

Initial Process:

Initially, I worked on creating a bomb class with its appropriate methods and attributes. Next, I focused on creating a game class with its methods and attributes. I also created a platform class but later realized that I did not need it. 

I first worked with simple shapes (circles) to see the movement of the bombs for my game. I had to create the release of the bombs first and create movement in them while making sure they do not pass the limits of the screen. After accomplishing the change of velocity direction whenever the circle touches a wall on the screen. Then I focused on adding platforms and making sure circles were also colliding and changing direction with the walls of the platform. Later, I focused on creating an array of bombs and creating instances of the class using the frameCount. 

 

After accomplishing the basic structure of the game, I focused on making different types of bombs and confirming they were placed on the correct platform. Later, I focused on identifying a game loss and finally speeding up the release of the bombs. 

 

The final process was making the initial screen and creating a way to start the game or see the instructions of the game. 

 

Using vectors:

When I first started working on the project, I started using individual variables for the velocity and position in the x and y-axis. However, after researching how to make objects collide, I became aware of the existence of a data type called PVector. After looking through the reference guide in Processing, I decided that using PVectors was much simpler than using different variables. Later, I got a better understanding in class when we worked on physics and coding. 

 

Designing part:

I decided to create my own designs for the background, initial screen, and characters. I first worked on creating the background. I decided to make the background look similar to the original game but with a different theme. The platform design was also inspired by the original platform design in the original game. For the characters, I first started by drawing a circle because I needed the characters to be based on a circle as I initially coded the game to recognize characters as circles. The characters, in this case, had a radius, and therefore designing them as circles were crucial to making the game work. The process of design was difficult because I had to create each element from scratch. For the characters, I only used real images for reference and the rest was completely designed by me.

Challenges:

There were several challenges I encountered while creating this game. Some of the major ones were:

 

Detecting the walls of the platform:

When I first started coding the collisions of the bombs and the platform, a part of the bomb was passing through the platform. I had difficulties in fixing this because every time I tried a different solution something wrong came up. For example, sometimes the bomb range was not covering all the space available, sometimes the bombs entered the platform and the game was ended, sometimes the change in direction of the bombs was not working. After several trials, I managed to fix this problem by looking through the code and figuring out what was wrong with the dimensions.

 

Detecting collisions between bombs:

When I first designed this game, I wanted to make collisions between the bombs so that when the player grabs a bomb, the mouse does not accidentally grab two objects at the same time. After some research in physics and collisions, I gave up on understanding this concept to implement so I decided to revert the velocity direction if a collision was detected. This was working fine at the beginning of the game but I realized problems when there were several instances of the bomb within the screen. Later, I changed the code of the game so that objects could overlap but the mouse could only grab one object at a time. This was the best solution I had approached. 

Design

The design process was more difficult than I first thought it would be. Creating the characters and calculating the spaces for the background was a challenge. I had to spend more time than I anticipated because sometimes the location of certain objects in backgrounds would not match with the code. There were also certain objects I created but did not use because I did not end up liking the background with such objects.

 

Conclusion:

I personally really enjoyed the creation of this game and I want to continue making it a better game. I spent a good amount of time making the code work and designing the visual part. At first, I thought it was a simple game to make but it actually ended up being more complicated than I thought it would be. The interaction of the game came out exactly as I wanted and I was satisfied with the visual part of the game. Still, there are certain parts that I would like to change in the future. First, the ending screens for the win and lose of the game are not visually appealing as I did not have the time to create a background for each. I also want to create a level system for the game in the future to make it more challenging. The game indicates a win after 90 bombs are sorted. Finally, one thing I would definitely implement is the part where a function calculates the time the bomb has not been sorted. Although there is a function that identifies if a bomb has not been sorted for a long time and ends the game, I would like to add something to have the player identify unsorted bombs such as making bombs blink or change color or size. Still, I think I am proud of the outcome of this project and I look forward to creating more game projects in the future. 

import processing.sound.*;
SoundFile sound;
int mode = 0; //Determines the mode of the background;
Game game;
Platform platform1, platform2;
boolean locked = false;
int score;
Screen screen;

void setup(){
  sound = new SoundFile(this, "soundfile.mp3");
  
  size(900, 600);
  frameRate(60);
  game = new Game();
  sound.loop(); //SOUND REQUIREMENT
}

void draw(){
  background(130);
  game.drawGame();
  
}
  
  
void mouseReleased(){
  game.checkrelease();
}
Bomb(){
    img[0] = loadImage("img1.PNG");
    img[1] = loadImage("img0.PNG");
    img[1].resize(60,60);
    img[0].resize(70,60);
    platformnum = 0;
    condition = 1;
    x = width/2;
    y = 40;
    velox = 0;
    veloy = random(1, 3);
    typecolor = (int)random(1, 3);
    typeplatform = typecolor;
    correctplat = typecolor;
    position = new PVector(x, y);
    velocity = new PVector(velox, veloy);
    radius = 40;
    plat1x = 0;
    plat2x = 600;
    platy = 150;
    platwidth = 300;
    platheight = 300;
    limitx1 = 300;
    limitx2 = width - 300;
    limity1 = 150;
    limity2 = height - 150;
    upperlimit = 0;
    if(typecolor ==1){
      colorbomb = color(98, 0, 246);
    }
    else if(typecolor == 2){
      colorbomb = color(255);
    }
  }
  
  
  //=========================================================
  void move(){
    
    position.add(velocity);
    
    if( position.x > width - radius/2 ) 
    {
     position.x = width - radius/2;
     velocity.x *= -1;
    }
    else if (position.x < radius/2)
    {
     position.x = radius/2;
     velocity.x *= -1;
    }
    else if (position.y > height - radius/2)
    {
     position.y = height - radius/2;
     velocity.y *= -1; 
    }
    else if (position.y < upperlimit + radius/2 )
    {
     position.y = upperlimit + radius/2;
     velocity.y *= -1;
    }
     
     
  }
  //=========================================================
  //Function used to keep track of time each bomb is on screen
  void updatetimeonscreen(){
    if(inplat == false){
      if(frameCount % 100 == 0){
        timeonscreen++;
      }
    }  
  }
  
  //=========================================================
  //Function to determine whether bomb should explode and game over should be called
  void explode(){
    //TO fill
    if(actualplat != 0){ // Determines whether a bomb is in the wrong platform
      if(actualplat != correctplat){
        gameover = true;
      }
    }
    else if(timeonscreen == 20){ //Determines whether a bomb has been for too long on screen
      gameover = true;
    }
  }
   
  void updatetint(){
    
    
  }
  //=========================================================
  //Function to detect collisions and change direction if collision is made
  void collision(Bomb b){
    //TO fill
    
    if(dist(position.x, position.y, b.position.x, b.position.y) < radius){
      velocity.x *= -1;
      velocity.y *= -1;
      b.velocity.y *= -1;
      b.velocity.x *= -1;
    }
  }
  
  //=========================================================
  //Function to determine whether bomb collides with a platform
  void collisionwithplatform()
  {
    
   if( ((position.x + radius + velocity.x > plat1x &&
   position.x - radius/2 + velocity.x < plat1x + platwidth) ||
   (position.x + radius/2 + velocity.x > plat2x &&
   position.x + velocity.x < plat2x + platwidth)) &&
   position.y + radius/2 > platy &&
   position.y - radius/2 < platy + platheight)
   {
     velocity.x *= -1;
   }
   
   if( ((position.x + radius/2 > plat1x &&
   position.x - radius/2 < plat1x + platwidth) ||
   (position.x + radius/2 > plat2x &&
   position.x < plat2x + platwidth)) &&
   position.y + radius/2 + velocity.y > platy &&
   position.y - radius/2 + velocity.y < platy + platheight){
   
     velocity.y *= -1;
   }
  }
  
  //=========================================================
  //Function indicating mouse released after mouse grabs bomb
  void release(){
    velocity.x = (random(0, 4)-2);
    tempvelox = velocity.x;
    tempveloy = velocity.y;
  }
  
  //=========================================================
  //Function setting the upperlimit after bomb is initially released
  void upperlimsetter(){
    upperlimit = 60;
  }
  
  //=========================================================
  //Function ton 
  void checkinplat(){
   if(position.x > radius &&
   position.x < limitx1 &&
   position.y > limity1 &&
   position.y < limity2){
     platformnum = 1;
     condition = 2;
     inplat = true;
     draggedbomb = 0;
     actualplat = 2;
     
   }
   else if(position.x > limitx2 &&
   position.x < width &&
   position.y > limity1 &&
   position.y < limity2){
     platformnum = 2;
     condition = 2;
     inplat = true;
     draggedbomb = 0;
     actualplat = 1;
   }   
  }
  
  //=========================================================
  void movementaftermouse(){
    if(releasedbymouse == true){ 
    velocity.x = tempvelox;
    velocity.y = tempveloy;
    releasedbymouse = false;
    draggedbomb = 0;
    controlledbymouse = false;
    }
  }
  
  //=========================================================
  void movementinplatform(){
    switch(platformnum){
      
      case 1:
        if( position.x > 300 - radius/2 ) 
        {
         position.x = 300 - radius/2;
         velocity.x *= -1;
        }
        else if (position.x < radius/2)
        {
         position.x = radius/2;
         velocity.x *= -1;
        }
        else if (position.y > limity2 - radius/2)
        {
         position.y = limity2 - radius/2;
         velocity.y *= -1; 
        }
        else if (position.y < limity1 + radius/2 )
        {
         position.y = limity1 + radius/2;
         velocity.y *= -1;
        }
        break;
        
      case 2:if( position.x > width - radius/2 ) 
        {
         position.x = width - radius/2;
         velocity.x *= -1;
        }
        else if (position.x < 600 + radius/2)
        {
         position.x = 600 + radius/2;
         velocity.x *= -1;
        }
        else if (position.y > limity2 - radius/2)
        {
         position.y = limity2 - radius/2;
         velocity.y *= -1; 
        }
        else if (position.y < limity1 + radius/2 )
        {
         position.y = limity1 + radius/2;
         velocity.y *= -1;
        }
        break;
    }
      
  }
  //=========================================================
  void updatescore(){
   if(inplat == true && scoreyes == 1){
     game.score++;
     scoreyes = 0;
     
   } 
  }
  
  //=========================================================
  void drawbomb(){
    if(controlledbymouse == true){
      position.x = mouseX;
      position.y = mouseY;
    }
    updatetimeonscreen();
    // Drawing the circles
    imageMode(CENTER);
    image(img[typecolor-1], position.x, position.y);
    move();
    explode();
    checkinplat();
    updatescore();
    if(position.y > 50 && position.y< 54){
       release();
    }
    if(position.y > 65){
      upperlimsetter();
    }
    switch(condition){
      case 1:
        collisionwithplatform();
        break;
      case 2:
        movementinplatform();
        break;
    }
    if(gameover == true){
      game.gameover = true;
    }
  }
 
      
    
}
class Game{
  Bomb bombarray[]; // Array storing the number of bombs
  int i; // Variable that counts the number of bombs created
  int velobombs; //Variable determining the velocity of creation of bombs
  int score = 0; //Variable containing the score of the game
  PImage[] background = new PImage[3]; // Array storing the images for backgrounds
  PImage buttons[];// Array storing images for buttons
  int condition; //Variable containing the 
  int backgroundimg;
  int casenum; //Case number for screen function.
  String scoretext;
  boolean gameover; // Variable to determine game over
  boolean gamewin; //Variable to determine game win
  int backgroundnum; // Background image index from array
  boolean restart = false; // variable to verify if restart of the game is allowed or not
  
  Game(){
    bombarray = new Bomb[100];
    i = 0;
    velobombs = 200;
    condition = 0;
    background[2] = loadImage("background2.png");
    background[1] = loadImage("background1.png");
    background[0] = loadImage("background0.png");
    casenum = 0;
  }

  //=========================================================
  //Function to create new bombs
  void createbomb(){
    bombarray[i] = new Bomb();
    i++;
  }
  
  //=========================================================
  //Function to check release of bombs if mouse is released
  void checkrelease(){
    for(int j=0; j < i; j++){
       if(bombarray[j].controlledbymouse == true){
         bombarray[j].controlledbymouse = false;
         bombarray[j].release();
         break;
       }
    }
  }
  
  //=========================================================
  //Function checking for bomb collision
  void checkcollisions(){
   for(int j=0; j < i; j++){
     for(int k=j+1; k < i; k++){
       bombarray[j].collision(bombarray[k]);
     }
   }
  }
  
  //=========================================================
  //Function to control the bomb if grabbed
  void controlbomb(){
    for(int j=0; j<i; j++){
      if(bombarray[j].controlledbymouse == true){
        break;
      }
      else if(bombarray[j].inplat == false){
        if(dist(mouseX, mouseY, bombarray[j].position.x, bombarray[j].position.y) < bombarray[j].radius/2){
           bombarray[j].controlledbymouse = true;
           break;
            }
         }
      }
  }  
    

  
  //=========================================================
  //Function to draw the Game
  void drawGame(){
    if(backgroundnum < 3){
      background(background[backgroundnum]);
    }
    
    if( i >= 89){
      gamewin = true;
    }
    
    //Controlling bombs
    if(mousePressed ){
      controlbomb();
    }
    
    //Screen with actual gameplay
    //Having bomb releases
    if(backgroundnum == 1){
      if(frameCount%(velobombs) == 0 && i <= 89 && gameover == false){
        createbomb();
      }
      
      //Make the release of bombs faster
      if(frameCount%1000 == 0){
       velobombs -= 10; 
      }
      
      for(int j=0; j < i; j++){
        bombarray[j].drawbomb(); 
      }
      //printing the score
      textSize(32);
      fill(0);
      text("Score: ", 50, 585);
      text(score, 150, 585);
      
      if(score >= 89){
        backgroundnum = 4;
      }
      
      if(gameover == true){
        backgroundnum = 3;
      }
    }
    
    // First Screen
    if( backgroundnum == 0 ){
      if(mouseX > 350 && mouseX < 550 && mouseY > 380 && mouseY < 430){
        noFill();
        stroke(255, 255, 0);
        rect(350, 380, 200, 50); //SHAPE REQUIREMENT
        if(mousePressed){
          backgroundnum = 1;
        }
      }
      else if(mouseX >350 && mouseX < 550 && mouseY >460 && mouseY < 510){
        noFill();
        stroke(255, 255, 0);
        rect(350, 460, 200, 50);
        if(mousePressed){
          backgroundnum = 2;
        }
      }
    }
      
    //Screen with Instructions
    if( backgroundnum == 2 ){
      if(mouseX > 700 && mouseX < 840 && mouseY > 480 && mouseY < 530 ){
        noFill();
        stroke(255, 255, 0);
        rect(700, 480, 140, 50);
        if(mousePressed){
          backgroundnum = 1;
        }
      }
    }
      
    //Screen with winning message
    if( backgroundnum == 3 ){
      background(51);
      textSize(48);
      fill(255);
      text("Game Over!", 340, 150);
      text("Press any key to restart the game", 70, 250); 
      restart = true;
    }
    
    //Screen with loosing message
    if( backgroundnum == 4 ){
      background(255, 204, 0);
      textSize(48);
      text("You won the game", 280, 200);
      text("Press any key to restart the game", 180, 250);
      restart = true;
    }
    
    if(restart == true){
      if(keyPressed){
        setup();
        sound.stop();
      }
    }
  }
  
}

The original game has music background from:

Summer Days by Roa https://soundcloud.com/roa_music1031 Creative Commons — Attribution 3.0 Unported — CC BY 3.0 Free Download / Stream: http://bit.ly/-summer-days Music promoted by Audio Library https://youtu.be/3wiksi3J_KI

 

ZIP FILE FOR CODE:

Midterm_RockHyungKang

 

Leave a Reply