How to make a card matching game in p5.js (memory)

I am trying to make a card matching game. But I don’t know how I can matching than when they are correct. Maybe I can let the first card and second card . But I don’t really know how to do it.
Link: p5.js Web Editor

 let images = [];
let visibleImages = new Array(16);
let x = 0;
function preload() {
  for (let j = 0; j < 8; j++) {
    let img = loadImage(j + 1 + ".jpg");
    images.push(img);
    images.push(img);
  }
}
function mouseClicked() {
  let cx = floor(mouseX / (width / 4));
  let cy = floor(mouseY / (height / 4));
  let imgIndex = cy * 4 + cx;
  visibleImages[imgIndex] = true;
}
function setup() {
  createCanvas(400, 400);
  visibleImages.fill(false);
  shuffle(images, true);
}
function draw() {
  background(255);
  for (let j = 0; j < 4; j++) {
    for (let i = 0; i < 4; i++) {
      square((i * 400) / 4, (j * 400) / 4, 400 / 4);
      let imgIndex = j * 4 + i;
      if (visibleImages[imgIndex] == true) {
        image(images[imgIndex], (i * 400) / 4, (j * 400) / 4, 400 / 4, 400 / 4);
      }
    }
  }
}
1 Like

Hi @yoyo,

Would you please follow the instructions and format your code…

ezgif.com-gif-maker (1)

For a starting point you can put your images to an object with an id. Afterwards you can compare if the id is the same.

Cheers
— mnse

3 Likes

Yeah!

Instead of using a class:
You also could load the image names into a String grid first.

Shuffle the string grid.

Load then the images into a second image grid (the one you already have)

Now you have the string names and can compare the names easily (numbers at start of String) to find out whether the 2 images match

next step

Have a counter for the mouse clicks. When it’s ==2 then compare the 2 open images, then reset. Thus you can distinguish between first and second mouse click.

remark

Also draw an image for images that are not open (the backside of each card), the same image for every card.

2 Likes

how can I load the image names into a String grid?

Replace this by

imageNames.push (j + 1 + ".jpg");
imageNames.push (j + 1 + ".jpg");

imageNames : declare this as a new array

1 Like

I am trying to do this but it seems something wrong. Can you tell me which step I did wrong?
Link: p5.js Web Editor

let images = [];
let visibleImages = new Array(16);
let imagesName = [];
let x = 0;
function preload() {
  for (let j = 0; j < 8; j++) {
    imagesName.push(j + 1 + ".jpg");
    imagesName.push(j + 1 + ".jpg");
    let img = loadImage(imagesName[j]);
    images.push(img);
    images.push(img);
  }
}
function mouseClicked() {
  let cx = floor(mouseX / (width / 4));
  let cy = floor(mouseY / (height / 4));
  let imgIndex = cy * 4 + cx;
  visibleImages[imgIndex] = true;
}
function setup() {
  createCanvas(400, 400);
  visibleImages.fill(false);
  shuffle(imagesName, true);
}
function draw() {
  background(255);
  for (let j = 0; j < 4; j++) {
    for (let i = 0; i < 4; i++) {
      square((i * 400) / 4, (j * 400) / 4, 400 / 4);
      let imgIndex = j * 4 + i;
      if (visibleImages[imgIndex] == true) {
        image(images[imgIndex], (i * 400) / 4, (j * 400) / 4, 400 / 4, 400 / 4);
      }
    }
  }
}

This part doesn’t belong there

After loading the names (after the for loop), first shuffle them.

Then load the images using the names (in a new for loop in setup()). Since the names are with duplicates you don’t load each image twice but just once

Thus we make sure that the two grids are parallel in the sense that the image name and its image are in the same cell of the grid. Only then can we do a comparison using the String name

  • Remember when comparing Strings later you can’t use == ; use s1.equals(s2) instead

now I can link the image name and the image. So I should create a equal.() to compare the name.
Do I need to create a vector first? Because I am just a newcomer in p5.js I actually don’t know about equal.() and createVector. Thanks a lot!!

Where you have this in mouseClicked (better use mousePressed()) introduce a counter as explained above.

counter ++;

if(counter==1) {
  let imgIndex1 = imgIndex;
}
else if(counter==2) {
  counter=0; // reset
  let imgIndex2 = imgIndex;
  If(imagesName[imgIndex1].equals (imagesName[imgIndex2] )) {
      // ok
      println ("good");
      }else 
      {
       // wrong 
       // close both cards again !!!
       visibleImages[imgIndex1] =false;
       visibleImages[imgIndex2] =false;
       println ("No.");
      }
}

  • counter :: make it a global variable, imgIndex1 and
    imgIndex2 as well

Good progress here!

This should be after the for loop, not inside of it

So it’s between the two for loops

how would it come up? or should I let the imgIndex1 and imgIndex2 be 0 at global first?

TypeError: Cannot read properties of undefined (reading ‘equals’) at /sketch.js:32:31

p5.js says:
[sketch.js, line 32] Cannot read property of undefined. Check the line number in error and make sure the variable which is being operated is not undefined.

1 Like

That’s okay, just say 0

We define them in mousePressed()

I don’t know what I did wrong???

:cherry_blossom: p5.js says:
[sketch.js, line 32] “equals” could not be called as a function.
Verify whether “imagesName[imgIndex1]” has “equals” in it and check the spelling, letter-casing (JavaScript is case-sensitive) and its type.

TypeError: imagesName[imgIndex1].equals is not a function
at /sketch.js:32:31

I don’t know.

Maybe I was wrong about .equals()... (probably true in processing but not in p5.js)

Just try

if (imagesName[imgIndex1] == imagesName[imgIndex2]) {
      // ok

You also need to count
correct pairs.

When == 8 you won

1 Like
counter ++;

if(counter==1) {
  let imgIndex1 = imgIndex;
}
else if(counter==2) {
  counter=0;
  let imgIndex2 = imgIndex;
  if(imagesName[imgIndex1].equals (imagesName[imgIndex2] )) {
      print ("good");
      }else 
      {
       visibleImages[imgIndex1] =false;
       visibleImages[imgIndex2] =false;
       print ("No.");
      }
}

I just found out about a problem. If I am doing this, the imgIndex1 a just define in the first if() . When counter ==2 , imgIndex1 become undefinded

  counter++;
  if (counter == 1) {
    let imgIndex1 = imgIndex;
  } else if (counter == 2) {
    counter = 0;
    let imgIndex2 = imgIndex;
    print(imgIndex1,imgIndex2)
    if (imagesName[imgIndex1] == (imagesName[imgIndex2])) {
      print("good");
    } else {
      visibleImages[imgIndex1] = false;
      visibleImages[imgIndex2] = false;
      print("No.");
    }
  }

the result of print(imgIndex1,imgIndex2) is

undefined, 6

and the result of the comparison to the image becomes 100% false

1 Like
let imgIndex1;
let imgIndex2;

define both before setup ()

Remove the let in the old position in the code

1 Like

OMG, I did it!!! Thank you guys

2 Likes

Do you have a You Won message?

1 Like