Ryan’s Midterm Project

Initial Stage

When I first started thinking about ideas for my Midterm Project, I simply thought of just finishing one of my unfinished Brick Breaker games. However, we were reminded that it should be original, so this first idea was out of the window.

Afterwards, I tried to think of an original and creative idea of mine like the other people by trying to get some inspiration from other games that are currently out there. However, still, nothing came into my mind. So, I decided to at least think of  a theme for my game first, and I managed to settle on the theme of the situation that we are all in together, which is covid 19.  I thought this was a pretty good theme to work with because I was hoping to make a game that can reflect the situation that we’re all in and at the same time raise people’s awareness of this global epidemic. At first, I wrote down a list of ideas that was covid themed while trying to see if it can be applied with the similar mechanics of other games.

However, I wanted to find a way to make this game a bit more casual or comical to alleviate the tension around our world that is caused by this whole epidemic. Coincidentally, the news about Donald Trump getting Covid was released and I thought that it was a perfect opportunity to incorporate him into my game by having the users be able to control him and make him wear a face mask. I also saw this chance to make my game act as a reminder for the public to always to wear a face mask, or else you will “lose” to Covid.

After deciding on my main idea that I’m going to work with, I proceeded to brainstorm on how I could make this a game. After a while, I decided on a game where the user will control a ball, and the main objective of the user is to try to touch and tag all of the other balls that are originally images of Donald Trump not wearing a face mask and change them into images of Donald Trump wearing a face mask by touching all of them within a time limit of 30 seconds.

Sketches of game layout and examples

(these are pictures of my notes and sketches for my game’s layout)

Images Used 

For my images, I simply just searched different png images of Donald Trump online (not that hard to find). But I had to manually crop out some of the background of the second image and convert it to a png file.

Donald Trump just being Donald Trump
Donald Trump wearing a face mask image

Background music 

Link: https://www.youtube.com/watch?v=xy_NKN75Jhw&list=PLya__OBTLMkONuQDu0kHDCrml2xuEINSi&index=1

Main Difficulties

Some of the major difficulties that I had encountered throughout this entire process range from simply just importing an image or sound file to coding for collision detection between the objects, changing of images upon contact, starting the game when the mouse is clicked within a certain shape, telling the game to stop after the timer ends or ending it before the timer when the user has successfully tagged all of the shapes, and many many more.

However, after talking to both Aaron and Jack , I was finally able to resolve a lot of the different problems that I had experienced (too much to even list them all out). But, at the same time, I have also learned a lot throughout this experience about how to code more efficiently or how to streamline a specific function to another if something is pressed or triggered, and all those stuff.

Zip File

IM_Midterm_Project_2

All the code 

import processing.sound.*;

Balls [] balls;//the [] brackets indicate an array; it contains a whole list of NPC balls
userBall myBall;// this calls forward the User Ball class in the name of "myBall"
Timer timer;
PImage Ballsimg;
PImage collidedBallImg;
boolean buttonPressed;
int buttonX, buttonY, buttonW, buttonH;
int amountcollided;//the amount of times that the balls have collided
String S= "You Win! \n Press the mouse to restart";
SoundFile backgroundmusic;
int gameState;
int numberofballs=10;

void setup() {
  size(1280, 800);
  gameState=0;
  //Assume the start button has not been pressed
  buttonPressed = false;

  //Parameters for the start button 
  buttonW=335;
  buttonH=100;
  textSize(buttonH);
  buttonX=(width-buttonW)/2;
  buttonY=(height-buttonH)/2;
  Ballsimg= loadImage("Donald Trump Face.png");
  collidedBallImg= loadImage("Donald Trump wearing Facemask.png");
  balls= new Balls [numberofballs];// this allows it to contain 10 of the NPC Balls; this calls the constructor 
  for (int i=0; i<balls.length; i++) {// as long as i is less than 10, it's going to keep on calling on the "Balls" constructor, basically creating new balls 
    balls[i]= new Balls(Ballsimg, collidedBallImg);
  }
  backgroundmusic= new SoundFile(this, "Instruction BG Music.mp3");
  myBall= new userBall();//calls on the userBall constructor to create the user Ball in the name of "myBall"
}

void draw() {
  background(255);
  //code for instructions and start button
  if (gameState==0) { //if the Start button is pressed, run the game code 
    //timer.showTimer();//shows the timer on screen
    fill(random(144), random(230), random(166));
    String Instructions= "Instructions: \n Use the arrow keys on your keyboard to control and move the ball around the screen. \n The objective of the game is to make all the other Donald Trump balls wear his mask properly, \n and you will do that by tagging or touching all of them within the time limit of 30 seconds. \n You win if you manage to make all the Donald Trump balls wear a mask. \n You lose if there are still remainig Donald Trump balls not wearing a mask when the time ends."; 
    textAlign(CENTER);
    textSize(20);
    text(Instructions, width/2, height/2-200);
    fill(random(255), random(255), random(255));
    rect(buttonX, buttonY+200, buttonW+65, buttonH);
    fill(255, 0, 0);
    textSize(50);
    text("PRESS TO START", buttonX+200, buttonY+200+buttonH-10);
  } else if (gameState==1) {//the gameplay screen with game code
    for (int i=0; i<balls.length; i++) {
      balls[i].drawBalls();//allows all the NPC balls to be drawn on the window
      balls[i].moveBalls();//allows all the NPC balls to move around the window
      balls[i].Ballscheckedge();//allows all the NPC balls to bounce of the edges of the window
    }
    collisiondetection();
    myBall.drawuserBall();
    timer.showTimer();//shows the timer on screen
  } else if (gameState==2) {//win
    //numberofballs+=1;
    background(0);
    fill(random(255), random(255), random(255));
    textAlign(CENTER);
    textSize(80);
    text(S, width/2, height/2);
    if (mousePressed) {
      reset();
    }
  } else if (gameState==3) {//lose
    String G="Time's Up! You Lose! Game Over";
    String R="Press the mouse to restart";
    background(0);
    fill(random(255), random(255), random(255));
    textAlign(CENTER);
    textSize(80);
    text(G, width/2, height/2);
    textSize(50);
    text(R, width/2, height/2+100);
    if (mousePressed) {
      reset();
    }
  }
}

//if the start button is pressed
void mousePressed() {
  if ( mouseX > buttonX && mouseX < buttonX+buttonW+65 && mouseY > buttonY+200 && mouseY < (buttonY+200)+buttonH) {
    //buttonPressed=true;
    gameState=1;
    backgroundmusic.play();
    timer= new Timer();
  }
}
//code to control the user's ball
void keyPressed() { //code for controlling the user's Ball by arrow keys
  if (keyCode== UP && myBall.locy-myBall.radius >=0) myBall.locy-=25;//if the y location of the user's Ball minus the radius of the ellipse is greater or equal to 0, it will move upwards
  else if (keyCode== DOWN && myBall.locy+myBall.radius <=height) myBall.locy+=25;
  else if (keyCode == LEFT && myBall.locx-myBall.radius>=0) myBall.locx-=25;
  else if (keyCode == RIGHT && myBall.locx+myBall.radius<= width) myBall.locx+=25;
}

void collisiondetection() {
  amountcollided=0;
  //putting in aloop for all of the NPC balls 
  for (int i=0; i<balls.length; i++) {
    //if the x and y location distance of any NPC ball and user ball added together is smaller than the radius of the NPC ball and user ball, then it means it has collided
    if (dist(balls[i].locx, balls[i].locy, myBall.locx, myBall.locy)< balls[i].radius + myBall.radius) {
      //println(dist(balls[i].locx, balls[i].locy, myBall.locx, myBall.locy));
      balls[i].iscollided=true; //if it collides, changes the boolean to true, changing the image
    }
    //each time it collides, the boolean is true, making the amountcollided to increment by 1
    if (balls[i].iscollided==true) {
      amountcollided+=1;
    }
  }
  println(amountcollided);
  //the the amount of collisions added up before the timer ends is greater or equal to 20
  if (amountcollided >=balls.length) {//if greater than the amount of balls in the game
    backgroundmusic.stop();
    gameState=2;
  }
}



//this is the state or the code from setup basically in order for the game to be restarted 
void reset() {
  //Assume the start button has not been pressed
  //buttonPressed = false;
  gameState=0;

  //Parameters for the start button 
  buttonW=335;
  buttonH=100;
  textSize(buttonH);
  buttonX=(width-buttonW)/2;
  buttonY=(height-buttonH)/2;
  Ballsimg= loadImage("Donald Trump Face.png");
  collidedBallImg= loadImage("Donald Trump wearing Facemask.png");
  balls= new Balls [numberofballs];// this allows it to contain 10 of the NPC Balls; this calls the constructor 
  for (int i=0; i<balls.length; i++) {// as long as i is less than 10, it's going to keep on calling on the "Balls" constructor, basically creating new balls 
    balls[i]= new Balls(Ballsimg, collidedBallImg);
  }
  backgroundmusic= new SoundFile(this, "Instruction BG Music.mp3");
  myBall= new userBall();//calls on the userBall constructor to create the user Ball in the name of "myBall"
}
class Balls {
  //basic information for building a bouncing ball
  float locx, locy;
  float ballwidth, ballheight;
  //these are the speed for all the balls; make it random to have different speed for each of them
  float xspeed=random(10);
  float yspeed=random(10);
  int radius=25;
  PImage Ballsimg;
  PImage collidedBallImg;
  boolean iscollided=false;
  

  Balls(PImage _img,PImage _collidedBallImg) {// this is my constructor or a setup function for my "Ball" object
   
    locx=random(width); //putting random will let the balls appear at different locations
    locy=random(height);
    ballwidth=2*radius;
    ballheight=2*radius;
    Ballsimg= _img;// this is inserting the image file loaded previously to every array of the NPC bouncing balls
    collidedBallImg= _collidedBallImg;// the donald trump w/ facemask image inserted for every array of NPC
}
  void drawBalls() {
    stroke(255,0,0);
    //ellipse(locx, locy, ballwidth, ballheight);
    imageMode(CENTER);
    if( iscollided==true){// if collided, it'll show this new collided image
      image(collidedBallImg, locx, locy, ballwidth+30, ballheight+20);
    }else{ //if not collided, it'll show this original image 
    image(Ballsimg, locx, locy, ballwidth+30, ballheight+20);
    }
  }
  void moveBalls() {//causes the NPC Balls to move around 
    locx+=xspeed;
    locy+=yspeed;
  }
  void Ballscheckedge() {//allows the Balls to bounce off the edges
    if (locx+radius >=width || locx+radius<=0) {
      xspeed*=-1;
    }
    if (locy+radius >=height || locy+radius<=0) {
      yspeed *=-1;
    }
  }
}
class Timer {
  float locx, locy;
  float timerwidth, timerheight;
  int countdown=30;
  int seconds; 
  float startTime;


  Timer() {// ask about the logic behind this and how to create a countdown timer? 
    textSize(50);

    startTime= millis()/1000 + countdown;
    seconds = int(startTime- millis()/1000);
  }
  void showTimer() {
    if (seconds<0) {
      startTime= millis()/1000 + countdown;//resets the timer and restarts it when less than 0
      //if seconds is zero, display "game over"
      backgroundmusic.stop();
      gameState=3;
      
    } else {
      seconds = int(startTime- millis()/1000);
      fill(255, 0, 0);
      text(seconds, width/2-100, 100);
    }
  }
}
class userBall {
  //pretty much the exact same as the NPC Balls
  float locx, locy;
  float ballwidth, ballheight;
  float xspeed=5;
  float yspeed=5;
  float radius=30;


  userBall() {//the constructor for this userBall object
    locx=width/2;
    locy=height/2;
    ballwidth=2*radius;
    ballheight=2*radius;
  }
  void drawuserBall() {
    fill(0);
    stroke(0, 0, 255);
    ellipse(locx, locy, ballwidth, ballheight);
  }
  
}

FINAL PRODUCT

Midterm – Meera.

When coming up with an idea for this game, I wanted to make a game that tends to the compulsiveness of having things be in order. I started out with just one white box in the center of my screen. I wanted the box to be spinning around itself, once I did that I added two more boxes the same size as the one in the middle. These boxes spun in different orders around themselves and the objective was to strategically make them stop , on command, at a moment they were all aligned. The game was set up with no way of winning, so a different approach was given. The next approach was to have the boxes orbit as though they were in a solar system. Now that the approach was changed the objective was altered too, the objective became that all the boxes must align around a straight horizontal line that went across the middle of the game window. After setting that up, a system of knowing that the boxes were aligned had to be made, and adding a start menu.

desgin notes 1

rotaysqay recoding

solar rotate align recording

boxes start menu and alignment text

 

 

 

Now I had to clean up the idea, I needed a theme and sound and text and better orbiting for my boxes. I started with my theme, I took inspiration from the movement of the boxes and decided on making the theme a solar theme. I put a yellow sun in the middle of my screen and made the boxes into orbiting spheres that circle around the sun. I added an image for my background but it glitched the orbiting spheres, my issue was that I was uploading the image as a pixel rather than just as an image.

 the was how it looked before I fixed it.

 

Once that was done, I working on the orbiting of my spheres. The problem was that only two spheres aligned at a time, it was mostly the outer sphere which was “ ellipse #3” that never aligned well. I messed around with three of the main components of the orbiting: the radian, the speed, and the radius (ring radius, or how far from the center each orbit ellipse is ). When I altered #3’s speed it made a difference but it still didn’t align them enough. I attempted a little with the radius but that did nothing to my alignment, so I ventured off to my final experiment which was the radian. I decreased the number of the radian in #3 and it got very close to the alignment, so I decided to increase the range of acceptance of a coded alignment. Once I did that, the player could finally win. I added text to help the player see that which sphere is aligned once paused.

 

 

Orbit fix

post space aligment clean up

 

Finally, I imported a sound file to the game. At first, I had the sound play when key was pressed, but since I started out with the code “ song.play();” it got chaotic every time the player paused for alignment.  Thus, I had the “ song.play();” moved up to the void setup, but now the sound ended even though the player is still playing. Therefore, I changed it to “ song.loop();” and it finally worked.

Finally, here’s the end result:

 

boolean paused = false;
float r;
float t;
float q;
float rX, rY;
float tX, tY;
float qX, qY;
float rSpeed, tSpeed, qSpeed;
int mode = 0;
PImage img;

//sound stuff
import processing.sound.*;
SoundFile song;

void setup() {
  size (800, 800);
  img = loadImage ("Space copy.jpg");
  rectMode(CENTER);
  r=radians(30);
  t=radians(40);
  q=radians(100);
  rSpeed = radians(1);
  tSpeed = radians(1.5);
  qSpeed = radians(.9);
  song = new SoundFile( this, "UpBeet copy.wav");
song.loop();
song.amp(.05);
}

void draw() {
  image(img, 0, 0);
  // if statment that take us to the start menu
  if (mode==0) {
    background(0, 0, 0);
    textAlign(CENTER);
    textSize(20);
    fill(40, 85, 56);
    text( " Press Space to Play  :)", width/2, height/2);
    textSize(16);
    fill(50, 100, 89);
    text (" align the grey circles as horizontally as possible, press 'p' on your keyboard to align.", width/2, height/2+30);
    drawStartScreen();
  }

  // if statment that take us from the start menu to the game 
  if (mode == 1) {

    // line in the center 
    line(0, height/2, width, height/2);

    //  center ellipse- ellipse#1
    //rotate(r);
    fill(255, 255, 0);

    ellipse(width/2, height/2, 60, 60);

    fill(55, 64, 80);
    float radius = 100;
    rX = cos(r) * radius + width/2;
    rY = sin(r) * radius + height/2;
    ellipse(rX, rY, 30, 30); // x,y,w,h


    //middle ellipse- ellipse#2

    tX = cos(t) * radius*2 + width/2;
    tY = sin(t) * radius*2 + height/2;

    ellipse(tX, tY, 30, 30); // x,y,w,h


    ////outer ellipse- ellipse#3
    qX = cos(q) * radius*3 + width/2;
    qY = sin(q) * radius*3 + height/2;
    ellipse(qX, qY, 30, 30); // x,y,w,h

    if (!paused) {
      r+= rSpeed;
      t+= tSpeed;
      q+= qSpeed;
    }

    // IF STATMENTS TO LET THE PLAYER KNOW HOW THEY'RE DOING : 
    //println(abs(rY-height/2));
    if (paused) {
      if (abs(rY-height/2)<40 ) {
        textSize(30);
        fill(0, 255, 0);
        text("sphere1: good job!", width/2, height/2+50);
      } else {
        textSize(30);
        fill(255, 0, 0);
        text("sphere1: try again..", width/2, height/2+50);
      }
    }
    if (paused) {
      if (abs(tY-height/2)<40) {
        textSize(30);
        fill(0, 255, 0);
        text("sphere2: good job!", width/2, height/2 +80);
      } else {
        textSize(30);
        fill(255, 0, 0);
        text("sphere2: try again..", width/2, height/2+80);
      }
    }

    if (paused) {     
      if (abs(qY-height/2)<40) {
        textSize(30);
        fill(0, 255, 0);
        text("sphere3: good job!", width/2, height/2 +120);
      } else {
        textSize(30);
        fill(255, 0, 0);
        text("sphere3: try again..", width/2, height/2+120);
      }
    }
  }
}

// the drawing for the start menu 
void drawStartScreen() {
}

// the function that created the Start menu
void keyPressed() {
  if (key==' ') {
    if (mode==0) {
      mode=1;
    } else if (mode==1) {
      mode=0;
    }
  }

}

// the function that pauses the game
void keyReleased() {

  if ( key == 'p' ) {

    paused = !paused;
  }
  //img.updatePixels();
  image(img, 0, 20);
}

ZIP:

https://intro.nyuadim.com/wp-content/uploads/2020/10/space_sound_Midterm_.pde_.zip

space_sound

(let me know if it’s still not working) :), updated nov 2

 

Image used for the background :

Midterm Project – Card Memory Game

Idea

When I was a child, I used to play this memory game that comes by default on every Windows 7 machine:

Memory Game, Windows

Hence the inspiration for my project.

Process

October 13, 2020.

Today marks the first day of my *official* work on the midterm project. I came up with an idea last week – the Card Memory Game. For now, I am doing some UI research to see what type of interface I would like to create for my staring page. I haven’t started my work yet, but I know for sure that I want to include some buttons and sounds. Today I also implemented a function for my button to check if it is being hovered over:

// check if the mouse is over the button
  boolean isHover(){
    if(mouseX <= rectX+rectWidth/2 
      && mouseX >= rectX - rectWidth/2
      && mouseY <= rectY + rectHeight/2
      && mouseY >= rectY - rectHeight/2)
      return true;
     else
       return false;
  }

October 14, 2020.

Keeping up the consistency! Worked on the Welcome UI scene, included some text instruction placeholders, built the button, and figured out how to move between the scenes (has some bugs, will improve next time).

October 16, 2020.

Fixed the function to switch between the scenes, designed the cards and made the cover for them. Created a function to load the card images into the array and display them in the second scene.

Making cards in Figma. Emoji design credits: imagiLabs.com

October 17, 2020

D e b u g g i n g

Debugging improper card deck display

<…>

October 26th, 2020.

Well, a lot of time has passed since my last update, but I was fixing the code here and there in the meanwhile. A few challenges during those few days was fixing the score to display on the screen properly (which I got fixed, yay!), displaying and shuffling the card deck properly (resolved!), storing the card flips (not resolved), and working out the complete logic of the game.

Final Notes

I believe it is worth mentioning that I got tremendous help along the way from Professor Aaron (thank you!), Professor Discord and Professor Google (xD). There were many things that I had to look up online, for example, the list shuffle method.

Does my program work perfectly now? No. Did I learn something new in the meanwhile? YES. Before embarking on this assignment, I had no clue how to switch between the game scenes, use lists and manipulate Java arrays dynamically. While my game still cannot count the score and flip the cards the way it is supposed to, I have learned that asking for help and needing some time to build a good code is normal and does not equal failing.

Demo

I have done the majority of the code, but have a tiny hidden bug somewhere that crashes the whole game. I suspect that happens somewhere between passing each card’s value and comparing selected cards, but I will investigate this further and am determined to make it work! Unfortunately, this might not happen on time for the showcase, but it will happen in the next few steps. For now, enjoy the code & demo:

// v0.4 24.10.2020
// importing sound
  import processing.sound.*;
  SoundFile click;

// v0.3 21.10.2020
// moving everything into class
  int margin = 3;
  IntList imageIndex = new IntList();
  int[] flippedCard;

// v0.2 17.10.2020
// Outputting the card deck

// v0.1 16.10.2020
// Creating different scenes + images

  // set the scene
  int scene, score;
  int numCards = 20;
  //PImage[] cards = new PImage[numCards];
  Card[] cards = new Card[numCards];
  PImage[] images = new PImage[numCards];
  PImage cardCover;

// v0.1 14.10.2020
// Creating the text instructions

  PFont font;
  String instructions_1, instructions_2, instructions_3, instructions_4, btn_start, btn_quit;
  int fontSize = 50;

// v0. 13.10.2020
// Creating a button

  // defining colors as [r,g,b] arrays
  int[] pink = {242, 170, 224};
  int[] green = {51, 225, 142};
  int[] orange = {248, 163, 15};
  int[] blue = {103, 212, 239};
  int[] yellow = {255, 244, 108};
  
  // defining shape coordinates
  float rectX, rectY, rectWidth, rectHeight;
  
  void setup(){
    size(1100, 800);
    rectMode(CENTER);
    click = new SoundFile(this, "clickSound.wav"); 
    scene = 0;
    
    // setting the button coordinates
    rectX = width/2;
    rectY = height/2;
    rectWidth = 170;
    rectHeight = 80;
    
    // setting the text
    push();
      fontSize = 40;
      instructions_1 = "Welcome!";
      instructions_2 = "You are presented a deck of cards.";
      instructions_3 = "Your task is to flip and match every one of them.";
    pop();
    
    btn_start = "START";
    btn_quit = "QUIT";
    font = createFont("VT323-Regular", fontSize);
    textFont(font);
    
    // setting flipped cards to null
    flippedCard = new int[2];
    score = 0;
    
    // load cards once
    loadCards();
  }
  
  void draw(){
    background(green[0], green[1], green[2]);
    // display scenes
    if (scene == 0){
      displayMenu();
    }
    if (scene == 1){
      playScene();
      //displayScore();
    }
    if (scene == 2){
      playWin();
    }
  }
    
  // display the UI scene
  void displayMenu(){
    
    // create a button
    push();
      noStroke();
      if(isHover())
        fill(yellow[0]-20,yellow[1]-20,yellow[2]-20);
      else
        fill(yellow[0],yellow[1],yellow[2]);
      rect(rectX, rectY, rectWidth, rectHeight);
    pop();
    
    // place instructions
    textAlign(CENTER);
    fill(0);
    text(instructions_1, width/2, height/6);
    text(instructions_2, width/2, height/6+80);
    text(instructions_3, width/2, height/6+120);
    text(btn_start, width/2, height/2+12.5);
    push();
      textSize(22);
      text("Intro to IM, Fall 2020", width/2, 3*height/4);
    pop();
  }
  
  // check if the mouse is over the button
  boolean isHover(){
    if(mouseX <= rectX+rectWidth/2 
      && mouseX >= rectX - rectWidth/2
      && mouseY <= rectY + rectHeight/2
      && mouseY >= rectY - rectHeight/2 && mousePressed){
      scene = 1;
      return true;
    }
     else
       return false;
  }
  
  // display scene 1
  void playScene(){
    background(blue[0], blue[1], blue[2]);
    
    // show the cards
    for (int i =0; i<numCards; i++){
      cards[i].displayCards();
    }
    push();
      textSize(60);
      text("Score: " + score, width-200, height/2);
    pop();
  }
  
  // load cards
  void loadCards(){
    
    // store all the cards in the image array
    for (int i = 0; i < numCards; i ++) {
      images[i] = loadImage(i+".png");
      imageIndex.append(i);
    }
    
    // initialize counters
    int counter = 0;
    int index;
    
    // initialize a deck matrix
    for (int i = 0; i < 5; i++) { //i = x
      for (int j = 0; j < 4; j++) {//j = y
        index = i + j * 5; // width is 5
        cards[index] = new Card(i*(margin+images[i].width), j*(margin+images[i].height), images[imageIndex.get(counter)], index);
        counter++;
      }
    }

    // shuffle images
    imageIndex.shuffle(); 
  }
  
  // flip the cards
  void mousePressed(){
    
     // add sound
     click.play();
    
     for (int i = 0; i<numCards; i++){
       cards[i].flipCard();

        if (flippedCard[0] == -1){
          flippedCard[0] = cards[i].value;
        }
        
        else{
          flippedCard[1] = cards[i].value;
        }
        // compare flipped cards
        if (flippedCard[0] != -1 && flippedCard[1] != -1){
          if (flippedCard[0] == (flippedCard[1] - 10) || flippedCard[0] == (flippedCard[1] + 10)){
            score++;
             // check for win
             if (score == numCards/2){
               scene = 2;
            }
          // flip cards back if they don't match
          else {
            cards[i].isFlipped = false;
          }
          // reset the storage array
            flippedCard[0] = -1;
            flippedCard[1] = -1;
          }
        }
      }
    }
  
  // display the win scene
  void playWin(){
     background(pink[0], pink[1], pink[2]);
     text("You have matched them all!", width/2, height/2-200);
     push();
      noStroke();
      if(isHover())
        fill(yellow[0]-20,yellow[1]-20,yellow[2]-20);
      else
        fill(yellow[0],yellow[1],yellow[2]);
      rect(rectX, rectY, 2*rectWidth, rectHeight);
    pop();
    text("Play Again?", rectX, rectY+10);
    score = 0;
    // reset the cards
    for (int i = 0; i < numCards; i++){
      cards[i].isFlipped = false;
    }
  }

class Card {
  PImage card;
  PImage cover;
  int locX, locY, value;
  int cardWidth = 135;
  int cardHeight = 200;
  boolean isFlipped = false;
  int numFlipped = 0;
  boolean isMatched = false;
  
  Card(int _locX, int _locY, PImage _card, int _value){
    locX = _locX;
    locY = _locY;
    card = _card;
    cover = loadImage("cover.png");
    value = _value;
  }
  
  void displayCards() {
    // display cover if not flipped
    if (!isFlipped && !isMatched){
      image(cover, locX, locY);
    }
    else {
      image(card, locX, locY);
    }
  }
  
  // debugging
  void displayValue(){
    print(value);
  }
  
  void flipCard(){
    if(mouseX <= locX+card.width 
      && mouseX >= locX
      && mouseY <= locY + card.height
      && mouseY >= locY){
       isFlipped = !isFlipped;
       
       // count every time the card is flipped
       numFlipped++;
       
       // reset the counter when 2 cards are selected
       if (numFlipped == 3){
         isFlipped = !isFlipped;
         numFlipped = 0;
       }
    }
  }
}

Zip file: amina_midterm

Midterm: MEMO game

Edit: I added a sound effect when flipping a card.

After some thinking, I decided to create a MEMO game for my midterm, a classic game with the goal to find matching pairs of cards. I though this would be a relatively easy way to incorporate different images into my project but it turned out more difficult than I expected as a lot of functionality is needed. This was challenging but thanks to support from Aaron, Jack, and various contributors to online forums, I managed to create a final product that I am happy with despite there being room for improvement and functionality I decided not to include in favor of healthy sleeping habits.

I first created a wireframe of the design I intended in Processing.
During the process, there were some scary moments.
I tested functionalities in different ways with print() functions and by placing simpler objects before placing colors for my cards.
First success: Images placed at the right locations.
All images added and placed.

When two clicked cards match, they remain face up and the player can try to find more matching pairs. They can also click the redo button which I incorporated into the title to return to the first screen and restart the game.

MEMO game screen recording

Intrigued? You can download the game here and play yourself.

Here is the code for the main tab:

//Game screens: 0: Initial Screen, 1: Game Screen

//for timer
int time;
int wait = 1000;

int gameScreen = 0;

PImage redo;
PImage abudhabi;
PImage berlin;
PImage clock;
PImage paris;
PImage people;
PImage stairs;
PImage tram;
PImage water;

Card[] cards;

IntList types; //to shuffle 16 cards of 8 different types
int showing; //to count how many cards are showing

int rows = 4;
int columns = 4;
int cardsize = 150;
int innerpadding = 15;
int outermargin = 20;
int cardstotal = (rows * columns);

void setup() {
  size(685, 855); //window size

  //load images
  redo = loadImage("redo.png");
  abudhabi = loadImage("abudhabi.jpg");
  berlin = loadImage("berlin.jpg");
  clock = loadImage("clock.jpg");
  paris = loadImage("paris.jpg");
  people = loadImage("people.jpg");
  stairs = loadImage("stairs.jpg");
  tram = loadImage("tram.jpg");
  water = loadImage("water.jpg");

  //add types of cards to IntList
  types = new IntList();
  types.append(0);
  types.append(0);
  types.append(1);
  types.append(1);
  types.append(2);
  types.append(2);
  types.append(3);
  types.append(3);
  types.append(4);
  types.append(4);
  types.append(5);
  types.append(5);
  types.append(6);
  types.append(6);
  types.append(7);
  types.append(7);
  types.shuffle();

  //create cards
  cards = new Card [16];

  int cardsinrow = 0;
  int cardsincolumn = 0;

  showing = 0; //keep track of how many cards are face up
  for (int i = 0; i < cards.length; i++) {
    cards[i] = new Card((outermargin + (cardsinrow * (cardsize + innerpadding))), (outermargin + (cardsincolumn * (cardsize + innerpadding))), types.get(i), i);
    cardsinrow++;
    if (cardsinrow >= columns) { // "Line break" for the cards
      cardsinrow = 0;
      cardsincolumn++;
    }
    //println(types.get(i));
  }
}

void draw() {
  if (gameScreen == 0) {
    initScreen(); //code in "initScreen" tab
  }

  if (gameScreen == 1) {
    //memoScreen(); //ideally simplify here and move code to "memoScreen" tab
    background(255);
    noStroke();
    //memo title
    pushMatrix();
    rectMode(CORNER);
    fill(0);
    rect(outermargin+innerpadding*0+cardsize*0, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
    rect(outermargin+innerpadding*1+cardsize*1, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
    rect(outermargin+innerpadding*2+cardsize*2, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
    fill(255);
    triangle(20, 20, 170, 20, 95, 80);
    rect(outermargin+innerpadding+cardsize+60, outermargin+40, 150-60, 20);
    rect(outermargin+innerpadding+cardsize+60, outermargin+cardsize-40-20, 150-60, 20);
    triangle(20+cardsize*2+innerpadding*2, 20, 170+cardsize*2+innerpadding*2, 20, 95+cardsize*2+innerpadding*2, 80);
    ellipseMode(CORNER);
    fill(0);
    ellipse(width-outermargin-cardsize, 20, cardsize, cardsize);
    popMatrix();

    //memo cards
    pushMatrix();
    imageMode(CORNER);
    translate(0, outermargin+cardsize); //to place cards below title
    //to store type and id of card that is flipped
    int[] type = {-1, -1};
    int[] ids = {-1, -1};
    int index = 0;

    for (int i=0; i < cards.length; i++) {
      cards[i].display();

      if (cards[i].show && !cards[i].matched) {
        type[index] = cards[i].type;
        ids[index] = cards[i].id;
        index++;
        //println(cards[i].id+": "+cards[i].type); //functionality testing
      }
    }
    if (type[0] != -1 && type[1] != -1) {
      if (type[0]==type[1]) {
        cards[ids[0]].matched = true;
        cards[ids[1]].matched = true;
        showing = 0;
      } else {
        if (millis() - time >= wait) {
          println("time passed");//functionality testing
          cards[ids[0]].show = false;
          cards[ids[1]].show = false;
          time = millis();//update the stored time
        }
        showing = 0;
      }
    }
    popMatrix();

    //redo symbol up right. when clicked on memoScreen return to initScreen.
    imageMode(CENTER);
    image(redo, 594, 94, 75, 75);
    //when redo image clicked, return to initScreen and reset
    if (mouseX >= width-outermargin-cardsize && mouseX <= width-outermargin && mouseY >= outermargin && mouseY <= outermargin+cardsize) {
      ellipseMode(CORNER);
      fill(0, 0, 0, 50);
      ellipse(width-outermargin-cardsize, 20, cardsize, cardsize);
      if (mousePressed == true) {
        gameScreen = 0;
        types.shuffle();
        for (int i=0; i<cards.length; i++) {
          cards[i].type = types.get(i);
          cards[i].matched = false;
          cards[i].show = false;
        }
      } else {
        return;
      }
    }
  }
}

void mousePressed() {
  if (gameScreen == 1) {
    for ( int t=0; t < cards.length; t++) {
      cards[t].mouseClick();
      time = millis();
    }
  }
}

Card class:

public class Card {

  int card1id, card2id, card1type, card2type;

  int cardposx;
  int cardposy;
  int type; //
  int id;
  boolean show;
  boolean pickCard;
  boolean matched;

  Card(int cardposx_, int cardposy_, int type_, int id_) { //add images
    cardposx = cardposx_;
    cardposy = cardposy_;
    type = type_; //to later assign images to different types
    id = id_; //will use t for now
    show = false; //meaning card does not show the image
    pickCard = true; //meaning card is able to be picked
    matched = false; //meaning card has not matched with another card yet
  }

  void display() {
    // ln(cardposx, cardposy, type, id); //testing
    if (!pickCard) { //card cannot be picked
      return;
    }
    if (!show) { //display blue rect as backside if cards do not show
      fill(0, 0, 255, 190); //card color slightly transparent to become fully blue when mouse hovers over
      if ( mouseOverCard() && showing < 2) {
        fill(0, 0, 255, 255); //stronger blue w/o transparency when mouse hovers over card
      }
      rect(cardposx, cardposy, cardsize, cardsize);
    } else {
      if (type == 0) { //change id to type after testing
        image(abudhabi, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 1) {
        image(berlin, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 2) {
        image(clock, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 3) {
        image(paris, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 4) {
        image(people, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 5) {
        image(stairs, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 6) { 
        image(tram, cardposx, cardposy, cardsize, cardsize);
      } else if (type == 7) {
        image(water, cardposx, cardposy, cardsize, cardsize);
      }
    }
  }

  boolean mouseOverCard() { //to determine when mouse hovers over a card
    //println(cardposx, cardposy, type, id); //testing
    if ( !pickCard ) {
      return( false );
    }
    return( mouseX >= cardposx && mouseX < cardposx+cardsize && mouseY >= cardposy+outermargin+cardsize && mouseY < cardposy+cardsize+outermargin+cardsize ); //need to add +outermargin+cardsize to Y location to account for translation of location under title
  }
  void mouseClick() {
    //time = millis();//store the current time
    //println(time);
    if ( !pickCard ) {
      return;
    } //nothing happens if card cannot be clicked
    if ( mouseOverCard() && !show && showing < 2) { // no more than two cards can be picked. only cards that do not show image already can be clicked //add && showing < 2
      show = !show;
      showing++;
      //println(showing); //functionality testing
    }
    if ( showing == 16) { //change this code
      gameScreen = 2;
    }
  }
  boolean sameType() { //check whether picked cards match meaning they have the same type
    return true; //just for testing
  }
}

First screen:

void initScreen() {
  // code of initial screen
  pushMatrix();
  background(0);

  //memo title
  fill(255);
  rectMode(CORNER);
  rect(outermargin+innerpadding*0+cardsize*0, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
  rect(outermargin+innerpadding*1+cardsize*1, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
  rect(outermargin+innerpadding*2+cardsize*2, outermargin+innerpadding*0+cardsize*0, cardsize, cardsize);
  ellipseMode(CORNER);
  ellipse(width-outermargin-cardsize, 20, cardsize, cardsize);
  fill(0);
  triangle(20, 20, 170, 20, 95, 80);
  rect(outermargin+innerpadding+cardsize+60, outermargin+40, 150-60, 20);
  rect(outermargin+innerpadding+cardsize+60, outermargin+cardsize-40-20, 150-60, 20);
  triangle(20+cardsize*2+innerpadding*2, 20, 170+cardsize*2+innerpadding*2, 20, 95+cardsize*2+innerpadding*2, 80);

  //game instructions
  textAlign(CENTER);
  textSize(50);
  fill(255);
  text("Find the matching pairs.", width/2, height/2-100);

  //example rects & "Play" button
  rectMode(CENTER);
  fill(0, 0, 255, 190);
  rect(width/2+50, height/2, 50, 50);
  rect(width/2-50, height/2, 50, 50);
  if (gameScreen == 0 && mouseX >= 270 && mouseX <= 420 && mouseY >= 408 && mouseY <= 458) {
    fill(0, 0, 255);
    rect(width/2+50, height/2, 50, 50);
    rect(width/2-50, height/2, 50, 50);
    if (mousePressed == true) { //mouseX >= 270 && mouseX <= 420 && mouseY >= 408 && mouseY <= 458 &&
      gameScreen = 1;
    }
  }
  fill(255);
  textSize(30);
  text("PL", width/2-50, height/2+13);
  text("AY", width/2+50, height/2+13);
  fill(0, 0, 255);
  text("=", width/2, height/2+13);


  //game instructions continued
  fill(255);
  textSize(20);
  text("Click to flip a card. Click another card.", width/2, height/2+100);
  text("Do that again and again.", width/2, height/2+135);
  text("Eventually you'll find all pairs.", width/2, height/2+170);
  text("Inshallah.", width/2, height/2+205);
  text("Ready? Click P L  A Y.", width/2, height/2+275);
  popMatrix();
}

Find an overview of my media sources here.

 

Shadows Game

Game concept

Shadows is a pathfinding game, where your goal is to find a treasure in an ancient labyrinth. The problem with that is, that no one was there for hundreds of years and it’s buried deep underground so there is no light in there. Surrounded by shadows you enter the labyrinth hoping to find its treasure.

Mechanics

The most important part of the game is the light mechanics. I decided that it would be super fun to create an actual labyrinth game, where you do not see the whole board from the very beginning and just navigate through it. In my game you will have to actually explore the labyrinth, memorize the paths and hopefully find the treasure.

Graphics

I used some tile sets for DnD found on the internet to create the labyrinth board.

Then I added the light layer and created the light source at my mouse coordinates:

Tomorrow I’m going to work on my character, the intro menu as well as the labyrinth hit boxes. Probably they will be the hardest part of the project after the lighting, but I’m sure I’ll figure something out.

Update

Having finished the game I might say that creating it was easier than I expected. The issue that I was concerned by the most was creating the hitboxes. Having such a complicated map with all the bending corridors would be horrendous to hardcode (as almost everything is lol).

In order to solve the hitbox issue I made use of the pixels array. Before the game begins an extra graphic is loaded, where all the pathways are white and all the rest is black. That simple graphic is then stored in pixels. During the game the only thing to do to check for hitboxes is simply checking the color value on the corresponding x,y in the presaved pixels array. If it is not black, the character can move. If it’s black it means they are in front of a wall.

Here is the graphic I prepared for the hitboxes function:

By this small chunk of code I managed to check the hitboxes for the whole map. It compares the x and y coordinates of the character with the corresponding color in the preloaded pixels array (it remains loaded with the above image). if the corresponding pixel is black, the character doesn’t change its position, as only when the pixel is white, dx and dy are added to its location correspondingly. I also took into account the dimensions of the character itself and the perspective of the 2.5D graphics. ScaleX and scaleY variables are responsible for proper scaling to lower screen sizes.

void didTouchHitbox() {
  if ((pixels[x+(y+1)*width-int(scaleX*20)]!=color(255, 255, 255) || pixels[x+int(y+20*scaleY)*width-int(scaleX*20)]!=color(255, 255, 255)) && dir==2) {}
  else if ((pixels[x+(y+1)*width+int(scaleX*20)]!=color(255, 255, 255) || pixels[x+int(y+20*scaleY)*width+int(scaleX*20)]!=color(255, 255, 255)) && dir==3) {}
  else if ((pixels[x+y*width-int(5*scaleX)]!=color(255, 255, 255) || pixels[x+y*width+int(5*scaleX)]!=color(255, 255, 255)) && dir==1) {}
  else if ((pixels[x+(y+int(30*scaleY))*width-int(5*scaleX)]!=color(255, 255, 255) || pixels[x+(y+int(30*scaleY))*width+int(5*scaleX)]!=color(255, 255, 255)) && dir==0) {}
  else {
    x+=dx;
    y+=dy;
  }
}

 

I do not want to post more graphics not to spoil the labyrinth for you guys, so I will just leave a screen from the menu 🙂

At last, here is my code. I’m quite happy as I managed to squeeze it into less than 300 lines.

Shadows

Happy maze solving 🙂

Week 6: Midterm Project

For the game I would like to do for this midterm,  I am developing a game I created a year ago called Sounds Like NYUAD.

  Concept:

The layout is the Nyuad campus, which I illustrated myself last year. The player’s goal is to find the hidden ‘sounds’ located in various NYUAD locations, and each sound is an addition to the final ‘song’ made up of NYUAD sounds. The sounds were also recorded, edited, and produced by me last year. In the song, there are sounds like the NYUAD birds, the Card Swipe, someone sneezing, and coughing (pre-covid times).

Implementation: 

The main thing I have to make sure of is that all sounds begin at the same time, but remain muted until they are triggered. This is because it is crucial that all the sounds play like one song, and stay on beat to the song I am playing. When the player comes close to the marker, the sound will be triggered, and that part is added.

 

Process: 

The game is currently coded on Python, and so translating it to Java is my first step. This is really exercising everything I learnt on Java, and also trying to keep track of which language I am using. Next I have some developments I would like to add, and bugs  I would like to fix.

  1. Adding a instruction page
  2. More clear indicator when you trigger a sound (and fixing the bug when it is repeated twice).
  3. Inidcating how many sounds are left
  4. Hints/clues where to find them
  5. Score calculated based on how many sounds + how fast
  6. Leadership list
  7. Fix bugs: such as cats and borders + A clear Indicator when you have hit a border

Sample: 

 

 

Game game;
Creature creature;
Borders borders;

void setup(){
    size(1024, 768);
    background(255, 255, 255);
    game = new Game ();
    creature = new Creature ();
    borders = new Borders ();
    

   
}

void draw (){
  game.drawGame();
}
class Borders{
  float x, y, x2, y2;
  
  Borders (){
  displayBorders();
  
  }
  
  void displayBorders(){
  stroke(200);
  line(x,y,x2,y2);
  }
}
class Creature{
  float x, y, r;
  float vy = 0;
  float vx = 0;
  //direction = RIGHT; 
  
  Creature (){
   updateCreature();
   noFill();
   noStroke();
   image( img, x-r, y-r, 50, 50);
   circle(x,y, r*2);
   
  }
  void updateCreature(){
    y += vy;
    x += vx;
  }
  
  //void distanceCreature(self, target){
  //  return ((self.x - target.x)**2 + (self.y - target.y)**2) **0.5;
  //}
  
}
import processing.sound.*;
PImage img, dead, won;
SoundFile backgroundSound;

class Game {
  float w, h, g;
  float count = 120;
  float scorecount = 0;
  boolean totalwin = false;
  
  
  Game(){
  img = loadImage("map.jpg");
  dead = loadImage("sorry.png");
  won = loadImage("finalpage.png");
  //backgroundSound = new SoundFile("OriginalBacktrack.mp3");
  //backgroundSound.play();
}

void drawGame (){
  image (img, 0,0);
  fill (0,0,0);
  textSize(25);
  text("Time Remaining: ", 365, 50);
  fill(255,255,255);
  //textSize(25);
  text("Time Remaining: ", 363, 48 );
}
}

Here is the python code of the original: (its really long and messy, so I have a lot of reorganzing to do)

#Ayham and Suzan final project

add_library('minim')
import os, random 
path = os.getcwd()
player = Minim(this)

class Creature: #creates both the cats and thomas
    def __init__(self, x, y, r):
        self.x = x
        self.y = y
        self.r = r
        self.vy = 0
        self.vx = 0
        self.direction = RIGHT 
        
        
    def display(self):
        self.update()
        noFill()
        noStroke()
        image(self.img, self.x -self.r, self.y-self.r, 50, 50)
        # fill(255, 255, 255)
        circle(self.x, self.y, self.r * 2)
        
    def update(self):
        self.y += self.vy
        self.x += self.vx
        
            
        
    def distance(self, target):
        return ((self.x - target.x)**2 + (self.y - target.y)**2) **0.5
        
   
        
        
class Cats(Creature): #the cats class
    def __init__(self, x, y, r, img, w, h,x1, x2):
        Creature.__init__(self, x, y, r)
        
        self.vx = random.randint(1,3)
        self.x1 = x1
        self.x2 = x2
        self.img = loadImage(path + "/images/" + img)
        print(x,y)
        
    def update(self):
    
        if self.x < self.x1: #movement of the cats
            self.direction = RIGHT
            self.vx *= -1
        elif self.x > self.x2:
            self.direction = LEFT
            self.vx *= -1
        
        self.y += self.vy
        self.x += self.vx

        
class Thomas(Creature): 
    def __init__(self, x, y, r):
        Creature.__init__(self, x, y, r)
        print(x,y)
        self.key_handler = {LEFT:False, RIGHT:False, UP:False,DOWN:False}                                                               
        self.alive = True
        self.img= loadImage(path + "/images/thomas.png" )
        self.ding_sound = player.loadFile(path + "/sounds/Ding.mp3") #plays when one song part is captured
        self.meow_sound = player.loadFile(path + "/sounds/meow.mp3") #plays when it gets killed by a cat
    

                
    def update(self):
        
    
    #movement of thomas
        if self.key_handler[LEFT] == True and not self.x < 0 :
            self.vx = -1
            self.direction = LEFT
        elif self.key_handler[RIGHT] == True and not self.x + self.r > game.w :
            self.vx = 1
            self.direction = RIGHT
        elif self.key_handler[UP] == True and not self.y < 0:
            self.vy = -1
            self.direction = UP
        elif self.key_handler[DOWN] == True and not self.y +self.r > game.h:
            self.vy = 1
            self.direction = DOWN
            
        else:
            self.vx = 0
            self.vy = 0
       
       #boundaries created for thomas
       
       #horizental boundaries
        if (self.vy+(self.r*1)+self.y >= game.borders1.y and 
            self.vy+(self.r*1)+self.y <= game.borders1.y2 and 
             self.vx+self.r+self.x >= game.borders1.x and 
             self.vx+self.r+self.x <= game.borders1.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders2.y and 
            self.vy+(self.r*1)+self.y <= game.borders2.y2 and 
             self.vx+self.r+self.x >= game.borders2.x and 
             self.vx+self.r+self.x <= game.borders2.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders5.y and 
            self.vy+(self.r*1)+self.y <= game.borders5.y2 and 
             self.vx+self.r+self.x >= game.borders5.x and 
             self.vx+self.r+self.x <= game.borders5.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders6.y and 
            self.vy+(self.r*1)+self.y <= game.borders6.y2 and 
             self.vx+self.r+self.x >= game.borders6.x and 
             self.vx+self.r+self.x <= game.borders6.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders7.y and 
            self.vy+(self.r*1)+self.y <= game.borders7.y2 and 
             self.vx+self.r+self.x >= game.borders7.x and 
             self.vx+self.r+self.x <= game.borders7.x2):
            
            self.vy=0
        
        if (self.vy+(self.r*1)+self.y >= game.borders9.y and 
            self.vy+(self.r*1)+self.y <= game.borders9.y2 and 
             self.vx+self.r+self.x >= game.borders9.x and 
             self.vx+self.r+self.x <= game.borders9.x2):
            
            self.vy=0
        
            
        if (self.vy+(self.r*1)+self.y >= game.borders12.y and 
            self.vy+(self.r*1)+self.y <= game.borders12.y2 and 
             self.vx+self.r+self.x >= game.borders12.x and 
             self.vx+self.r+self.x <= game.borders12.x2):
            
            self.vy=0
        
        
        
        if (self.vy+(self.r*2)+self.y >= game.borders15.y and 
            self.vy+(self.r*2)+self.y <= game.borders15.y2 and 
            self.vx+self.r+self.x >= game.borders15.x and 
            self.vx+self.r+self.x <= game.borders15.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders25.y and 
            self.vy+(self.r*1)+self.y <= game.borders25.y2 and 
             self.vx+self.r+self.x >= game.borders25.x and 
             self.vx+self.r+self.x <= game.borders25.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders27.y and 
            self.vy+(self.r*1)+self.y <= game.borders27.y2 and 
             self.vx+self.r+self.x >= game.borders27.x and 
             self.vx+self.r+self.x <= game.borders27.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders30.y and 
            self.vy+(self.r*1)+self.y <= game.borders30.y2 and 
             self.vx+self.r+self.x >= game.borders30.x and 
             self.vx+self.r+self.x <= game.borders30.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders31.y and 
            self.vy+(self.r*1)+self.y <= game.borders31.y2 and 
             self.vx+self.r+self.x >= game.borders31.x and 
             self.vx+self.r+self.x <= game.borders31.x2):
            
            self.vy=0
            
        if (self.vy+(self.r*1)+self.y >= game.borders33.y and 
            self.vy+(self.r*1)+self.y <= game.borders33.y2 and 
             self.vx+self.r+self.x >= game.borders33.x and 
             self.vx+self.r+self.x <= game.borders33.x2):
            
            self.vy=0
        
            
            #vertical
        if (self.vx+(self.r*2)+self.x <= game.borders3.x and 
            self.vx+(self.r*2)+self.x >= game.borders3.x2 and 
            self.vy+self.r+self.y <= game.borders3.y and 
            self.vy+self.r+self.y >= game.borders3.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders4.x and 
            self.vx+(self.r*2)+self.x >= game.borders4.x2 and 
            self.vy+self.r+self.y <= game.borders4.y and 
            self.vy+self.r+self.y >= game.borders4.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders8.x and 
            self.vx+(self.r*2)+self.x >= game.borders8.x2 and 
            self.vy+self.r+self.y <= game.borders8.y and 
            self.vy+self.r+self.y >= game.borders8.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders11.x and 
            self.vx+(self.r*2)+self.x >= game.borders11.x2 and 
            self.vy+self.r+self.y <= game.borders11.y and 
            self.vy+self.r+self.y >= game.borders11.y2):
        
            self.vx = 0
        
        if (self.vx+(self.r*2)+self.x <= game.borders16.x and 
            self.vx+(self.r*2)+self.x >= game.borders16.x2 and 
            self.vy+self.r+self.y <= game.borders16.y and 
            self.vy+self.r+self.y >= game.borders16.y2):
        
            self.vx = 0
        if (self.vx+(self.r*2)+self.x <= game.borders19.x and 
            self.vx+(self.r*2)+self.x >= game.borders19.x2 and 
            self.vy+self.r+self.y <= game.borders19.y and 
            self.vy+self.r+self.y >= game.borders19.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders21.x and 
            self.vx+(self.r*2)+self.x >= game.borders21.x2 and 
            self.vy+self.r+self.y <= game.borders21.y and 
            self.vy+self.r+self.y >= game.borders21.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders22.x and 
            self.vx+(self.r*2)+self.x >= game.borders22.x2 and 
            self.vy+self.r+self.y <= game.borders22.y and 
            self.vy+self.r+self.y >= game.borders22.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders23.x and 
            self.vx+(self.r*2)+self.x >= game.borders23.x2 and 
            self.vy+self.r+self.y <= game.borders23.y and 
            self.vy+self.r+self.y >= game.borders23.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders24.x and 
            self.vx+(self.r*2)+self.x >= game.borders24.x2 and 
            self.vy+self.r+self.y <= game.borders24.y and 
            self.vy+self.r+self.y >= game.borders24.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders26.x and 
            self.vx+(self.r*2)+self.x >= game.borders26.x2 and 
            self.vy+self.r+self.y <= game.borders26.y and 
            self.vy+self.r+self.y >= game.borders26.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders28.x and 
            self.vx+(self.r*2)+self.x >= game.borders28.x2 and 
            self.vy+self.r+self.y <= game.borders28.y and 
            self.vy+self.r+self.y >= game.borders28.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders29.x and 
            self.vx+(self.r*2)+self.x >= game.borders29.x2 and 
            self.vy+self.r+self.y <= game.borders29.y and 
            self.vy+self.r+self.y >= game.borders29.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders32.x and 
            self.vx+(self.r*2)+self.x >= game.borders32.x2 and 
            self.vy+self.r+self.y <= game.borders32.y and 
            self.vy+self.r+self.y >= game.borders32.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders34.x and 
            self.vx+(self.r*2)+self.x >= game.borders34.x2 and 
            self.vy+self.r+self.y <= game.borders34.y and 
            self.vy+self.r+self.y >= game.borders34.y2):
        
            self.vx = 0
            
        if (self.vx+(self.r*2)+self.x <= game.borders35.x and 
            self.vx+(self.r*2)+self.x >= game.borders35.x2 and 
            self.vy+self.r+self.y <= game.borders35.y and 
            self.vy+self.r+self.y >= game.borders35.y2):
        
            self.vx = 0

        
        self.y += self.vy
        self.x += self.vx
        

            
        
            
        
        #sounds of the song and functions to when the song is detected
        if  library.distance(self) < 20:
            self.ding_sound.rewind()
            self.ding_sound.play() 
            game.library.setGain(1)
            library.win = True
            # showimage()
        if knocknock.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.knocknock.setGain(1)
            knocknock.win = True
        if  alarm.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.alarm.setGain(1)
            alarm.win = True
        if  baraha.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.baraha.setGain(1)
            baraha.win = True
        if  dining.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.dining.setGain(1)
            dining.win = True
        if  palms.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.palms.setGain(1)
            palms.win = True
        if  theatre.distance(self) <20:
            self.ding_sound.rewind()
            self.ding_sound.play()
            game.theatre.setGain(1) 
            theatre.win = True  
                
        for g in game.cats: #cats distribution
            if g.distance(self) <= self.r+ g.r:
                self.meow_sound.rewind()
                self.meow_sound.play()
                self.alive = False
        

            
       
        

        
class Locations(): #locaitions for the song parts
    def __init__(self, x, y,r ):
        self.x = x
        self.y= y
        self.r= r
        self.win= False
    
    def display(self):
        noFill()
        noStroke()
        circle(self.x, self.y, self.r)
 
    def distance(self, target):
        return ((self.x - target.x)**2 + (self.y - target.y)**2) **0.5
        

        
class Borders():
    def __init__(self,x,y,x2,y2):
        self.x = x
        self.y= y
        self.x2 = x2
        self.y2 = y2
        
    
    def display(self):
        stroke(200)
        line(self.x,self.y,self.x2,self.y2)
    
        
       
                        
class Game:
    def __init__(self, w, h, g):
        self.w = w
        self.h = h
        self.g = g
        self.img = loadImage(path + "/images/map.jpg")
        self.dead = loadImage(path + "/images/sorry.png")
        self.won = loadImage(path + "/images/finalpage.png")
        self.background_sound = player.loadFile(path + "/sounds/OriginalBacktrack.mp3")
        self.background_sound.play()
        self.baraha = player.loadFile(path + "/sounds/CardSwipe.mp3")
        self.baraha.setGain(-1000)
        self.baraha.play()
        self.knocknock = player.loadFile(path + "/sounds/Knock_RA.mp3")
        self.knocknock.setGain(-1000)
        self.knocknock.play()
        self.theatre = player.loadFile(path + "/sounds/SneezeCough.mp3")
        self.theatre.setGain(-1000)
        self.theatre.play()
        self.library = player.loadFile(path + "/sounds/Typing_clicking.mp3")
        self.library.setGain(-1000)
        self.library.play()
        self.palms = player.loadFile(path + "/sounds/Birds.mp3")
        self.palms.setGain(-1000)
        self.palms.play()
        self.dining = player.loadFile(path + "/sounds/Didyoudothereading.mp3")
        self.dining.setGain(-1000)
        self.dining.play()
        self.alarm = player.loadFile(path + "/sounds/iPhoneAlarm.mp3")
        self.alarm.setGain(-1000)
        self.alarm.play()
        self.thomas = Thomas(75,450,15)
        self.count = 120
        self.scorecount=0
        self.totalwin= False
        
#border coordinates 
        self.borders1 = Borders(444 , 286, 575, 286) #horizental
        self.borders2 = Borders(442 , 346, 520, 346)#horizental 
        self.borders3 = Borders(540 , 455, 540, 346) #V
        self.borders4 = Borders(582 , 456, 582 , 286) #V
        self.borders5 = Borders(402,470,502,470) #H
        self.borders6 = Borders(590,472,712,472)#H 
        self.borders7 = Borders(754,493,812,493)#H
        self.borders8 = Borders(874,541,874,509)#V
        self.borders21 = Borders(948,620,948,533)#V
        self.borders22 = Borders(158,370,158,182)#V
        self.borders23 = Borders(775,720,775,675)#V
        self.borders24 = Borders(800,720,800,675)#V
        self.borders25 = Borders(530,527,586,527)#h
        self.borders26= Borders(586,595,586,527)#V
        self.borders27 = Borders(536,595,586,595)#h
        self.borders28 = Borders(536,595,536,529)#V
        self.borders29 = Borders(396,664,396,614)#v
        self.borders30 = Borders(350,614,396,614)#h
        self.borders31= Borders(754,602,808,602)#h
        self.borders32 = Borders(808,640,808,602)#V
        self.borders33 = Borders(756,640,808,640)#h
        self.borders34 = Borders(756,640,756,602)#V
        self.borders35 = Borders(418,281,418,189)
        self.borders9 = Borders(50,195,470,195)#H
        self.borders11 = Borders(65,300,65,360)#V
        self.borders12 = Borders(65,375,422,375)#H
        self.borders15 = Borders(356,725,950,725)#H
        self.borders16 = Borders(340,750,340,572)#V
        self.borders19 = Borders(955,750,955,640)#V
       
        
        
        #appending the cats in the game
        self.cats = []
        for i in range(3):
            self.cats.append(Cats(random.randint(200, 900), random.randint(200, 600), 15, "cat" + str(random.randint(1,3))+".png", 70, 70, 200, 800))

        
    def display(self):
        image(self.img,0,0)
        fill(0,0,0)
        textSize(25)
        text("Time remaining: "+ str(self.count), 365, 50 )
        fill(255,255,255)
        textSize(25)
        text("Time remaining: "+ str(self.count), 364, 49 )
        if self.count == 0: #stop the game when the game is over
            self.thomas.alive = False
            self.background_sound.close()
            self.baraha.close()
            self.palms.close()
            self.library.close()
            self.dining.close()
            self.theatre.close()
            self.knocknock.close()
            self.alarm.close()
            
        if self.thomas.alive == False: 
            image(self.dead, 187, 59)
            self.background_sound.close()
            self.baraha.close()
            self.palms.close()
            self.library.close()
            self.dining.close()
            self.theatre.close()
            self.knocknock.close()
            self.alarm.close()
            
            return
        if library.win == True and alarm.win == True and palms.win == True and baraha.win == True and theatre.win == True and knocknock.win == True and dining.win == True: #winning of the game 
            self.totalwin= True
            image(self.won, 187, 59)
            self.background_sound.close()
            self.baraha.close()
            self.palms.close()
            self.library.close()
            self.dining.close()
            self.theatre.close()
            self.knocknock.close()
            self.alarm.close()
            return

            
        self.thomas.update()
        self.thomas.display() 
                    
        for g in self.cats:
            g.display() 
   
 #coordinates of the different sounds   
game = Game(1024, 768, 585)
library = Locations (250,270,100)
palms = Locations(250,470,100)
baraha = Locations (400, 310, 50)
theatre = Locations (790, 250, 100)
dining= Locations (950, 400, 100)
knocknock= Locations (800, 620, 200)
alarm= Locations (570, 570, 200)


            
def setup():
    size(game.w, game.h)
    background(255, 255, 255)

def draw():
    print(game.thomas.x,game.thomas.y)
    
    if game.thomas.alive == True and game.totalwin== False :
        if frameCount % 60 ==0:
            game.count -= 1
        print(game.scorecount)
        
    game.display()
    library.display()
    palms.display()
    baraha.display()
    theatre.display()
    dining.display()
    knocknock.display()
    alarm.display()
    
         

def keyPressed(): #aids in movement using the keys
    if keyCode == LEFT:
        game.thomas.key_handler[LEFT] = True
       
    elif keyCode == RIGHT:
        game.thomas.key_handler[RIGHT] = True
    elif keyCode == UP:
        game.thomas.key_handler[UP] = True
    elif keyCode == DOWN:
        game.thomas.key_handler[DOWN] = True
    
def keyReleased():
    if keyCode == LEFT:
        game.thomas.key_handler[LEFT] = False
    elif keyCode == RIGHT:
        game.thomas.key_handler[RIGHT] = False
    elif keyCode == UP:
        game.thomas.key_handler[UP] = False 
    elif keyCode == DOWN:
        game.thomas.key_handler[DOWN] = False 
        
    
def mouseClicked(): 
    global game
    if game.thomas.alive == False or game.totalwin== True: #clicks when game is over 
        game = Game(1024, 768, 585)
    

 

Midterm Project Update

The game is about fighting COVID-19 by the use of your fighting tools [handwash, facemask, and faceshield] the COVID-19 cells will fall from the top of the screen and if you shoot them, you get points but the number of fighting tools decrease. If the cells reaches the bottom of the screen the number of cases go up. The objective of the game is to keep the number of cases as low as possible.

For the midterm project the progress so far has been planning the game on paper. As seen below. As of right now on processing the code consists of a game class file and a main file.

The game class file will encapsulate all the game state and will be responsible for displaying the game stats and and updating them. The game class attributes are:

  1. points
  2. cases
  3. handwash
  4. masks
  5. shields
  6. state
  7. fightTool
  8. time
  9. And the icons

The game class methods are:

  1. increment points
  2. reduce points
  3. increment cases
  4. increment masks
  5. decrement masks
  6. increment shields
  7. decrement shields
  8. increment handwash
  9. decrement handwash
  10. change state
  11. update time
  12. drawGameStats

The icons for use in the game were downloaded from flaticon as seen below

 

class Game {
  // attributes
  int points = 0;
  int cases = 0;
  int handwash = 20;
  int masks = 14;
  int shields = 6;
  int state = 0; // 0->shooting 1-> buying -1 -> gameOver
  int fightingTool = 0; // 0-handwash, 1-mask, 2-shield
  int time = 120;
  PImage maskImg = loadImage("mask.png");
  PImage handwashImg = loadImage("handwash.png");
  PImage shieldImg = loadImage("shield.png");
  int timeDisplay = 0;


  //methods
  void incrementPoints() {
    if (fightingTool == 0) {
      points += 1;
    } else if (fightingTool == 1) {
      points += 3;
    } else if (fightingTool == 2) {
      points += 5;
    }
  }
  void reducePoints(int fightingTool) {
    if (state==1) {
      if (fightingTool == 1) {
      }
    }
  }
  void incrementCases() {
    cases+=1;
  }

  void incrementMasks() {
    masks+=1;
  }

  void decrementMasks() {
    masks-=1;
  }

  void incrementShields() {
    shields+=1;
  }

  void decrementShields() {
    shields-=1;
  }

  void incrementHandwash() {
    handwash+=1;
  }

  void decrementHandwash() {
    handwash-=1;
  }

  void changeState() {
    if (state==0) {
      state=1;
    } else if (state==1) {
      state=0;
    }
  }
  void updateTime() {
    if (time==0) {
      state=-1;
    }
    if (frameCount%60==0 && state!=-1) {
      time-=1;
      if (timeDisplay==0) {
        timeDisplay = 1;
      } else if (timeDisplay==1) {
        timeDisplay=0;
      }
    }
  }

  void drawGameStats() {
    color(0, 0, 0);
    imageMode(CENTER);

    // draw mask
    image(maskImg, 70, 30, 30, 30);
    text(masks+" x", 25, 30);

    //draw handwash
    image(handwashImg, 150, 30, 30, 30);
    text(handwash+" x", 110, 30);

    // draw faceshield
    image(shieldImg, 230, 30, 30, 30);
    text(shields+" x", 190, 30);

    //display time
    pushStyle();
    textSize(30);
    if (timeDisplay==1) {
      fill(0, 0, 0);
      text(time, width-100, height-30);
    } else if (timeDisplay==0) {
      fill(255, 255, 0);
      text(time, width-100, height-30);
    }
    popStyle();

    // game mode
    pushStyle();
    int rectWidth = 100;
    int rectHeight = 30;
    int cornerRadius = 10;
    noFill();
    rect(width/2-rectWidth/2, 20, rectWidth, rectHeight, cornerRadius, cornerRadius, cornerRadius, cornerRadius);
    if (state==0) {
      pushStyle();
      textAlign(CENTER);
      textSize(25);
      fill(255, 0, 0);
      text("FIGHT", width/2, 45);
      popStyle();
    }

    popStyle();
    
    //display points
    pushStyle();
    fill(0,0,0);
    textSize(25);
    text(points+" points", width-300,45);
    text(cases+" cases", width-150,45);
    popStyle();
  }
}

 

Midterm Progress – Oct 18th

It took me a while to come up with an idea for my midterm project. I started out by looking up games online in the hopes of getting inspired by one of them. But that got me nowhere.
So, I started to think about events from my personal life that I could possibly base my game on. That’s when I got the idea to make one of my dreams/nightmares the inspiration for the game.
Unfortunately, I’m not the type of person who remembers their dreams once they wake up. However, I used to have a recurring “nightmare” when I was a kid that I, luckily, still remember.
I’m very claustrophobic. So, I used to have a nightmare where I would be in a room with a cake. The cake would get progressively bigger until it left me with no space for myself. My only way out was to eat it.
This will be the concept of the game: Eat the cake or it will “eat” you. ( it will take up all your space)

game concept

The game would start out with a character (me) and a cake (mean huge cake) in a room.
The cake can shoot the character. Each time it is able to hit it, it will grow a little bit more in size.
The character can move around, jump, and crouch to avoid the cake’s hits.
It can also take a bite out of the cake every time it gets close enough to it, and presses a specific keyboard key.
If the cake fills up the entire room, I lose. If I am able to eat it first, I win.

progress

I haven’t had much time to get a lot done because of my busy schedule this week. However, I decided to start working on some basics individually and make sure they work smoothly, so that I can later easily incorporate them into my game.

So far:

      •  I made a start menu template with buttons allowing me to move between screens (start menu, instructions, and gameplay):

      • I made functions to move my character to the right and left, and to jump:

 

Week 6 – Midterm Progress

I’ve spent a lot of time this week blurting out ideas for the code of my game. I just sat there and filled page upon page with notes, lists, and bullet points to try to figure out what logic is suitable for my game and how I could get it to function. By the end of that brainstorming session, I flipped through what I wrote…a little terrified by starting because it felt like there’s so much to think about.

The Idea

Last week, while brainstorming for this project, I realized that I’ve never seen anyone making a children’s game in this class or Intro to CS and thought it would be an interesting thing to explore. I think I also got a little too excited about the design possibilities that a project like this would give me.

So, I’m going for a spelling game, where a visual of an animal is displayed on the screen and the child has to click on letter blocks on the screen to spell out the animal’s name. When they get it right, the animal sound is triggered and they move on to the next level which presents an animal with a name more difficult to spell.

What I Have So Far

This weekend I got a few things done:

  • Made a list of classes needed and their properties
  • Finalized the list of animals I’m going to use (the levels)
  • Researched some games online to understand switching between different displays/windows
  • Planned my logic (the variables I need, what my logic could look like)
  • Started coding by creating a Button, Animal, and Letter class as well as a very simple start screen (only a start button).

I’m at a point where I kind of know what I need to do, but not sure how to organize it. So I’m hoping that talking through it today and spending more time breaking it down could make it easier to approach.

 

 

 

Midterm Progress… (“COVID-19 affects virtually nobody”)

My midterm project underwent several changes (and will undergo some more) during the past week.

With 2020 coming to an end and after all of what we have gone through with this coronavirus pandemic, it would have been a shame if I did not make at least one of my projects in this class have a theme of COVID-19.

I imagined a game where a character is moved by the user around the screen while holding a hand sanitizer using which they fire shots at the incoming corona particles. I imagined that there would be two terrified characters, a couple who are the main character’s elderly parents and who would remain inside the house which has its interior visible to the user from the outside. I wanted the main character to try to prevent the particles from reaching their parents inside the house or else they would lose the game.

perspective of a house with the parents inside

But then I thought that the game might not be as I want it to be because the interior of the house must be of some relevance to the functionalities where the character should be able to get inside or climb up the stairs for example, which would be unnecessary coding that I do not see as being worth it. In addition, I felt like it was very similar to other online games I have seen which makes it redundant.

Furthermore, I decided to change the idea a bit my making the fight not involve any parents but rather be inside a house and a character tries to protect themselves from being hit by the virus particles to survive.

two floor house in which the fighting takes place
another version of a two floor house

 

 

 

 

I imagined that the player can, for example, go from floor to the other by running into one of the edges of the screen, and that they keep moving and shooting until they take down all of the corona particles.

The idea was actually better now for me and I decided that this character would best suit what I want to do in general, even if I have to alter the background to be more appealing design-wise.

sprites of the main character which I found to be the most suitable at first

But then after further research I found some sprites of the US president Donald Trump and I then thought that I can make my game political! I decided that I can make it be outside the White House and the main character would be Trump. The game would be of satirical nature and makes fun of the disastrous way the president dealt with the coronavirus pandemic allowing for the USA to be reportedly the number one country with COVID-19 cases worldwide.

sprites of the trump character I used

Trump would try to kill the coronavirus particles with the ability to run only on the grass and jump once if the spacebar is pressed. I also decided to print out his most famous quotes about the pandemic, which were the most controversial, and let them fall down from the sky on banners to add to the excitement of the game.

white house background which I am currently using for the game

I want to add power-up facial masks which act as some sort of temporary shield for Trump while dodging the corona particles’ attacks. I decided to use this sanitizer and this “bullet” for shooting.

sanitizer used as a gun

 

bullet shot from sanitizer

 

 

 

 

I am still very unsure about my next steps and I hope to get a better sense of direction after meeting Aaron during today’s class.