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

Leave a Reply