Matching (memory) Game

Has anyone ever programmed two players Memory game in Processing in simple code and wants to share their code?

How do you turn player1 or player2?
How do you build screen switching? (start screen to score screen or end screen)
How can the two players enter their names and use these names later for the scores?

1 Like

Yes. I did.

Do you have an assignment?

Chrisir

1 Like

Yep. You’ll probably want to structure your code something like:

int state;

void seup(){
  size(600,400);
  state = 0;
}

void draw(){
  background(0);
  switch( state ){
    case 0:
      draw_name_entry_one();
      break;
    case 1:
      draw_name_entry_two();
      break;
    case 2:
      draw_in_game();
      break;
    case 3:
      draw_result_screen();
      break;
    default:
      background(200,0,0);
  }
}

void keyPressed(){
  switch(state){
    // Etc.
  }
}

void mousePressed(){
  switch(state){
    // Etc.
  }
}

void draw_name_entry_one(){
  // Etc.
}

// Etc...
4 Likes

here…

see tutorials for

  • arrays and
  • objects and
  • two-dimensional objects:

https://www.processing.org/tutorials/


// demonstrates mouse usage with states.
// one 2D array buttons holds all the screen buttons.
// 2 user names can be entered.  

// states:
// consts (numbers must be unique)
final int stateSplashScreen  = 0; // start screen
final int stateName1         = 1;
final int stateName2         = 2;
final int stateGame          = 3;  
final int stateGameOver      = 4;
int state  = stateSplashScreen;       // current 
final int stateMAX = stateGameOver+1; // the max number 

// 2D array of buttons. 
// First index = state, 2nd index = number of button in that state
RectButton[][] buttons = new RectButton [stateMAX][3]; 

// for the tool tip text 
int timeSinceLastMouseMoved=0;

// messages --------------------
String msgText="";
float msgX=0;
float msgY=0;
boolean msgShow=false;
int msgFrameCount = 0;

// text field 
boolean textFieldCursorIsOn = true; // cursor on / off? 
String enteredText = "";  // temp input text

// player names 
String namePlayer1 = "";  // results
String namePlayer2 = "";

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

// colors
final color colWhite      = color(255);
final color colBlack      = color(0);
final color colDarkGray   = color(111);
//---
final color colRed        = color(255, 0, 0);
final color colGreen      = color(0, 255, 0);
final color colBlue       = color(0, 0, 255);
//---
final color colYellow     = color(244, 244, 44);
final color colDarkYellow = color(255, 200, 120);

// colors for Buttons 
final color col1 = #ff0000;
final color col2 = #ffff00;
final color col3 = #000000;


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

void setup() {
  // init (runs only once)
  size(800, 800);

  // pre-init btns: set all to non-exist
  for (int i = 0; i<stateMAX; i++) {
    for (int i2 = 0; i2<buttons[i].length; i2++) {
      buttons[i][i2] =  new RectButton( 366, 3, 
        66, 70, col1, col2, false, "", "");
    }
  }

  // init btns

  // -------------
  // stateSplashScreen
  buttons[stateSplashScreen][0] =  new RectButton( 396 + 9, 433, 
    66, 70, col1, col2, true, "Next", "Go on, click me") ;

  // -------------
  // state name 1
  buttons[stateName1][0] =  new RectButton( 396 + 9, 433, 
    66, 70, col1, col2, true, "Next", "Go on, click me") ;

  // -------------
  // state name 2
  buttons[stateName2][0] =  new RectButton( 396 + 9, 433, 
    66, 70, col1, col2, true, "Next", "Go on, click me") ;

  // -------------
  // stateGame
  buttons[stateGame][0] =  new RectButton( 396 + 9, 433, 
    66, 70, col1, col2, true, "Hello", "Say Hello");

  buttons[stateGame][1] =  new RectButton( 396 + 9, 533, 
    66, 70, col1, col2, true, "Bye", "Say Bye");

  // -------------
  //stateGameOver
  buttons[stateGameOver][0] =  new RectButton( 396 + 9, 433, 
    66, 70, col1, col2, true, "Return", "return to game");
} // func 

void draw() { 
  // draw() runs on and on 

  getDataToDecideIfToolTipText();

  switch (state) {

  case stateSplashScreen:
    handleStateSplashScreen(); 
    break;

  case stateName1: 
    handleStateName1(); 
    break; 

  case stateName2: 
    handleStateName2(); 
    break; 

  case stateGame: 
    // Game
    handleStateGame();
    break; 

  case stateGameOver:
    // GameOver
    handleStateGameOver(); 
    break;

  default:
    // error
    println("Error number 939; unknown state : " 
      + state + ". Abort. #######################################");
    exit();
    break;
  } // switch
  //
} // func 

// ------------------------------------------------
// functions for states - called from draw() 

void handleStateSplashScreen() {
  background(11);
  fill(244, 3, 3); // red 
  text ("This is the Splash Screen....\n", 210, 313);
  showButtons();
} // func 

void handleStateName1() {
  background(11);
  fill(244, 3, 3); // red 
  text ("This is the Name state: PLAYER 1....\n", 210, 313);
  // draw the rest (the same for both states)
  handleInput();
} // func 

void handleStateName2() {
  background(11);
  fill(244, 3, 3); // red 
  text ("This is the Name state: PLAYER 2....\n", 210, 313);
  // draw the rest (the same for both states)
  handleInput();
} // func 

void handleInput() {
  // draw the rest 
  // (the same for both states) 
  //TextField
  fill(255);
  textSize(18);
  rect(25, 645, 200, 40);
  fill(0);
  text(enteredText+blinkChar(), 25+5, 645+30);
  fill(255, 2, 2, 11);
  toggleTextFieldCursorIsOn(); 
  // btns 
  showButtons();
}

void handleStateGame() {
  // Game
  background(11);
  fill(244, 3, 3); // red
  text (namePlayer1
    + " versus " 
    + namePlayer2
    + " <<<<<<<<<<<<<<<-------------", 
    17, 19);

  fill(244, 3, 3); // red 
  text ("This is the Game....\n"
    +" Don't touch the red rectangle...", 
    210, 313);

  noStroke();
  fill(255, 2, 2) ;
  rect(100, 100, 100, 100);
  fill(255, 2, 255) ;
  // rect(300, 100, 100, 100);

  if (mouseX > 100 && mouseX < 100 + 100  &&
    mouseY > 100   && mouseY < 100 + 100) {
    println ("collide");
    // change state
    timeSinceLastMouseMoved = millis();
    state = stateGameOver;
  }

  // btns
  showButtons();

  // message ----
  if (msgShow) {
    fill(colWhite);
    text (msgText, msgX, msgY); 
    if ( frameCount > msgFrameCount + 100 )
      msgShow=false;
  }//if
  //
} // func 

void handleStateGameOver() {
  // Game over / Lost 
  background(255);
  fill(244, 3, 3); // red 
  text ("You LOST....  ", 210, 313);
  text ("Hit any key to start Game", 210, 385);
  showButtons();
} // func 

// ----------------------------------------
// input keyboard

void keyPressed() {

  switch (state) {

  case stateSplashScreen: 
    // splash screen
    // do nothing 
    break; 

  case stateName1:
  case stateName2:
    // the same for both names
    //    if (keyCode>=32) 
    //      enteredText = enteredText + key;
    // SEE keyTyped() 
    break;

  case stateGame: 
    // Game
    // do nothing 
    break; 

  case stateGameOver:
    // Game Over
    timeSinceLastMouseMoved = millis();
    state = stateGame; 
    break;

  default:
    // error
    println("Error number 1039; unknown state : " 
      + state + ".");
    exit();
    break;
  } // switch
} // func 

void keyTyped() {
  // correct states? 
  if ( state == stateName1 || state == stateName2) {
    // yes 
    final char k = key;

    // quit?
    if (k == CODED)  
      return; // quit

    final int len = enteredText.length();

    if (k == BACKSPACE) {
      // shorten text   
      enteredText = enteredText.substring(0, max(0, len-1));
    } else if (len >= 44) { 
      return; // quit
    } else if (k == ENTER || k == RETURN) {
      // ignore
    } else if (k == TAB & len < 44-3) {
      // ignore 
      // tbox.txt += "    " ;
    } else if (k == DELETE) { 
      enteredText = ""; // reset
    } else if (k >= ' ') {  
      enteredText += str(k); // add this letter
    } // else if
  } // if
}

// ----------------------------------------
// input mouse

void mousePressed() {

  // reset timer for mouse over tool tip text  
  timeSinceLastMouseMoved = millis();

  // loop over all buttons (i) in the current state
  // when you add a new state, this func can stay the same 
  for (int i = 0; i<buttons[state].length; i++) {
    buttons[state][i].update();
    if (buttons[state][i].Exists && buttons[state][i].pressed()) {
      executeButton(state, i);
    }// if
  }//for
}//func

// ------------------------------------------ 
// tools

void showButtons() {
  // loop over all buttons (i) in the current state
  // when you add a new state, this func can stay the same 
  for (int i = 0; i<buttons[state].length; i++) {
    buttons[state][i].update();
    buttons[state][i].display();
    buttons[state][i].toolTip();
  } // for
} // func 

void executeButton(int stateLocal, int btnNumber) {
  // this is the command center for all states and all buttons : 
  // when you add a new state, you have to add something here.  
  switch(stateLocal) {
    // now the states: 

  case stateSplashScreen:
    // Splash Screen
    switch(btnNumber) {
    case 0:
      timeSinceLastMouseMoved = millis();
      state=stateName1;  // go on
      break; 
    default:
      // error
      println("Error number 1122; unknown button: " 
        + btnNumber
        + " in state: "
        + state 
        + ". Abort. #######################################");
      exit();
      break;
    } // inner switch
    break; 

  case stateName1:
    // only 1 btn
    namePlayer1 = enteredText;
    enteredText="";
    state=stateName2;   // go on
    break;

  case stateName2:
    // only 1 btn
    namePlayer2 = enteredText;
    enteredText="";
    state=stateGame;   // go on
    break;

  case stateGame:
    // game  
    switch(btnNumber) {
    case 0:
      println("Hello");
      msgOn("Hello ", 500, height-100);
      break; 
    case 1:
      println("Bye");
      msgOn("Bye ", 500, height-100);
      break; 
    default:
      // error
      println("Error number 1123; unknown button: " 
        + btnNumber
        + " in state: "
        + state 
        + ". Abort. #######################################");
      exit();
      break;
    } // inner switch
    break;

  case stateGameOver:
    // GameOver
    switch(btnNumber) {
    case 0:
      timeSinceLastMouseMoved = millis();
      state=stateGame; 
      break;    
    default:
      // error
      println("Error number 1124; unknown button: " 
        + btnNumber
        + " in state: "
        + state 
        + ". Abort. #######################################");
      exit();
      break;
    } // inner switch
    break;

  default:
    // error
    println("Error number 1339; unknown state : " 
      + state 
      + ". Abort. #######################################");
    exit();
    break;
    //------
  }// outer switch
}//func

void getDataToDecideIfToolTipText() {
  // get some data to decide if it is time to show tool tip text 
  if ((mouseX!=pmouseX) || (mouseY!=pmouseY)) {
    // mouse moved 
    // store time since last mouse moved 
    timeSinceLastMouseMoved = millis();
  }
}// func

void msgOn(String txt1, int x1, int y1) {
  msgText=txt1;
  msgX=x1;
  msgY=y1;
  msgShow=true;
  msgFrameCount = frameCount;
}

String blinkChar() {
  // returns a cursor or nothing 
  return (textFieldCursorIsOn) ? "|" : "";
}

void toggleTextFieldCursorIsOn() {
  // changes textFieldCursorIsOn 
  if (frameCount%30==0)
    textFieldCursorIsOn=!textFieldCursorIsOn;
} 

// =========================================
// class RectButton and Button  

class RectButton extends Button {

  // constr 
  public RectButton(int ix, int iy, 
    int isizeX, int isizeY, 
    color icolor, 
    color ihighlight, 
    boolean iExist, 
    String iText, 
    String iToolTipText 
    ) {
    x = ix;
    y = iy;

    sizeX = isizeX;
    sizeY = isizeY;    

    basecolor = icolor;
    highlightcolor = ihighlight;
    currentcolor = basecolor;
    Exists = iExist;

    Text = iText;
    ToolTipText = iToolTipText;
  } // constr 

  void display() {
    if (Exists) {
      stroke (ButtonStrokeColor); 
      strokeWeight(0); 
      fill(currentcolor, 30);
      rect(x, y, sizeX, sizeY);        
      if (Text != "") {
        //
        fill(0, 102, 153);
        textAlign(CENTER);
        textSize(16) ;
        text(Text, (x + (sizeX / 2.0)), (y + (sizeY / 2.0))+5);
        textAlign(LEFT);
      } // if (Text != "")
    } // if exists
  } // method display
} // class

class Button {
  int x, y;
  int sizeX;
  int sizeY;  
  color basecolor, highlightcolor;
  color currentcolor;
  boolean Exists  = false;  
  String Text     = "";
  String ToolTipText = ""; 
  //  String Tag = "";
  //  int Tag2 = 0;
  //  int TagMark = 0; 
  color ButtonStrokeColor = color (255, 255, 255);

  void update() {
    if (over()) {
      // Mouse over 
      currentcolor = highlightcolor;
    } else {
      // not Mouse over 
      currentcolor = basecolor;
    }
  } // update 

  void toolTip() {
    if (over()) {
      if (!ToolTipText.equals("")) {
        if (millis() - timeSinceLastMouseMoved > 800) {
          fill(colYellow);
          noStroke();
          textSize (12);
          float tw = textWidth(ToolTipText);
          float xLeft = mouseX-(tw/2); 
          float xRight = mouseX-(tw/2) + tw; 
          float xLeftText = mouseX; 
          if (xRight>=width) { 
            xLeft= width-tw-2;
            xLeftText= xLeft + tw/2;
          } 
          if (xLeft< 2) 
          { 
            xLeft=2;
            xLeftText= 2 + tw / 2;
          }
          rect (xLeft, mouseY+32, tw+4, 20);
          textAlign(CENTER);
          fill(0);
          text(ToolTipText, xLeftText, mouseY+44);
          textAlign(LEFT);
          textSize(16);
        } //  if
      } // if
    } // if
  } // func 

  boolean pressed() {
    if (over()) {
      return true;
    } else {
      return false;
    }
  }  // pressed; 

  boolean over() {
    if (overRect(x, y, sizeX, sizeY) ) {
      return true;
    } else {
      return false;
    }
  } // over 

  boolean overRect(int x, int y, 
    int width, int height) {
    if (mouseX >= x && mouseX <= x+width &&
      mouseY >= y && mouseY <= y+height) {
      return true;
    } else {
      return false;
    }
  } // overRect
  //
} // class
//
2 Likes

It’s not a related to memory but I’ve made a turn-based game using Processing that I’ve called Outspread that supports 2-4 players.

Code available here.

2 Likes

@Chrisir, Thanks for helping me!
Yes, here is my assignment.

@TfGuy44
Thanks, that is very useful!

thanks for sharing this and welcome to this forum!

We gave you some code. Please work from there.

We can’t do the homework for you. That’s the Codex of the forum.

You can ask questions here when you have a concrete issue.

Chrisir

@Chrisir
Thanks!
I certainly want to do this, but I wanted to know how to get started?
I have already started the assignment and I know enough how to do most of the parts, but I find those three screens difficult to achieve.
I will continue with the assignment and thanks again for all of you!

the screens in the assignment are the states in my example.

It’s easy to achieve with the variable state.

1 Like

In my sketch you can insert the game and later a high score.

My sketch is more like an empty template without decoration and stuff. It shows the different screens though, did you run it?

During the actual game you have a boolean variable player1Turn (indicating whose turn it is) and after each move you change this variable. If the cards matched (set a variable weGotAMatch to store this information) you add to the variable int player1Score or player2Score respectively:

if (weGotAMatch) {

weGotAMatch=false;

if (player1Turn) 
player1Score++;
else player2Score++;

}

// toggle
player1Turn= 
     ! player1Turn;

It’s a long project and there is no short cut really. But we are here to help.

Chrisir

1 Like

If you work from my template it’s essential that you understand it. More or less.

That’s your starting point.

Beautify the screen layout and make some headlines such as MEMORY !

Then you need a bunch of images, eg young kittens. Get them from web.

And you need one image as a Cover for the backside. Eg a question mark or just the word memory. You could do this programmatically but why.

Now since you work with different sizes of the board you need a way to enter this size. Or you work with a fixed size first.

Let’s say you use object oriented programming, like I did with my buttons.

What data does each Card hold? Position…?

Load the images. Distribute each one twice on the cards and store which are the pairs… pitfalls included…

Then in a nested for loop determine the position of each card and display it in another for loop.

A lot to do. Print out this post and tick off each point when done