Processing match 3

I’m making a match 3 game or at least I think it still called match 3. Anyways you click on a block and all the blocks touching that one of the same type vanish too. My problem is diagonal blocks are being chosen instead of the ones to the right, left, up & down.
in this pic here you can see it chose a box to the upper left which it shouldn’t be able to do.
screen

main

int s = 50;

ArrayList<Block> block = new ArrayList<Block>();
ArrayList<Spawner> spawn = new ArrayList<Spawner>();
int minH = 50;
int w = 5;
int h = 5;
int blockTimer = 0;
int chainN = 0;
boolean chose = false;
void setup(){
  size(600,600);
  reset();
}

void reset(){
  for (int i = 0; i < w; i++){
    spawn.add(new Spawner(25 + (s * i), minH + ((h-1) * s)));
  }
}

void draw(){
  background(0);
  textSize(20);
  text("B: " + blockTimer,5,20);
  text("ChainN: " + chainN,50,20);
  if (blockTimer >= 0 && chose == true){
    blockTimer -= 1;
  }
  /*if (blockTimer < 0 && chainN >= 1){
    if (chainN >= 3){
      for (int i = 0; i < block.size(); i++){
        Block b = block.get(i);
        if (b.chain == true){
          b.destroy = true;
        }
        b.coll = false;
        chainN = 0;
        chose = false;
        blockTimer = 0;
      }
    }
    if (chainN < 3){
      for (int i = 0; i < block.size(); i++){
        Block b = block.get(i);
        b.chain = false;
        b.click = false;
        chainN = 0;
        chose = false;
        blockTimer = 0;
      }
    }
  }*/
  for (Spawner s: spawn){
    s.show();
    s.create();
  }
  for (Block b : block){
    b.move();
    b.show();
    b.checked();
  }
  
  for (int i = block.size()-1; i >= 0; i--){
    Block b = block.get(i);
    if (b.destroy == true){
      block.remove(i);
    }
  }
}

void keyPressed(){
  if (key == 'r'){
    for (Block b: block){
      b.destroy = true;
    }
    for (Spawner s: spawn){
      s.coll = false;
    }
  }// r
  if (key == ' '){
    if (blockTimer < 0 && chainN >= 1){
      if (chainN >= 3){
        for (int i = 0; i < block.size(); i++){
          Block b = block.get(i);
          if (b.chain == true){
            b.destroy = true;
          }
          b.coll = false;
          chainN = 0;
          chose = false;
          blockTimer = 0;
        }
      }
      if (chainN < 3){
        for (int i = 0; i < block.size(); i++){
          Block b = block.get(i);
          b.chain = false;
          b.click = false;
          chainN = 0;
          chose = false;
          blockTimer = 0;
        }
      }
    }
  }
}

void mousePressed(){
  for (int i = 0; i < block.size(); i++){
    Block b = block.get(i);
    if (b.check == true){
      b.click = true;
      b.chain = true;
      chainN = 1;
    }
  }
}

spawner

class Spawner{
  PVector pos;
  int timer = 0;
  boolean coll = false;
  
  Spawner(int x, int y){
    pos = new PVector(x,y);
  }
  
  void show(){
    if (coll){fill(0);}
    if (coll == false){fill(125,125,125);}
    rect(pos.x,pos.y,s,s);
  }
  
  void create(){
    for (int i = 0; i < block.size(); i++){
      Block b = block.get(i);
      if (b.pos.y == pos.y && b.pos.x == pos.x){
        coll = true;
        break;
      } else{
        coll = false;
      }
    }
    if (timer >= 0){timer -= 1;}
    if (timer < 0 && coll == false){
      float r = random(2);
      r = round(r);
      block.add(new Block(pos,int(r)));
      timer = 64;
    }// timer
  }// create
}

block

class Block{
  PVector pos;
  int moveSpd = 0;
  boolean coll = false;
  int type = 0;
  boolean check = false;
  boolean click = false;
  boolean chain = false;
  boolean destroy = false;
  
  Block(PVector p, int type){
    pos = p.copy();
    this.type = type;
  }
  
  void checked(){
    if (chainN < 1){
      if (mouseX >= pos.x && mouseX <= pos.x + s && 
          mouseY >= pos.y && mouseY <= pos.y + s){
        check = true;
      } else {
        check = false;
      }
    } else {
      check = false;
    }
    if (click == true){
      for (int i = 0; i < block.size(); i++){
        Block b = block.get(i);
        if (b.type == type){
          if (b.pos.y == pos.y && b.pos.x == pos.x + s && b.chain == false ||
              b.pos.y == pos.y - s && b.pos.x == pos.x && b.chain == false ||
              b.pos.y == pos.y + s && b.pos.x == pos.x && b.chain == false ||
              b.pos.y == pos.y + s && b.pos.x == pos.x && b.chain == false){
            chain = true;
            b.chain = true;
            b.click = true;
            click = false;
            chainN += 1;
            blockTimer = 32;
            chose = true;
          }
        }
      }
    }
  }
  
  void show(){
    if (type == 0){fill(255,0,0);}// red
    if (type == 1){fill(0,255,0);}// green
    if (type == 2){fill(0,0,255);}// blue
    if (type == 3){fill(255,255,0);}// yellow
    if (type == 4){fill(255,0,255);}// purple
    if (type == 5){fill(0,255,255);}// cyan
    if (type == 6){fill(255, 165, 0);}// orange
    if (check == true){fill(255,255,255);}
    rect(pos.x,pos.y,s,s);
    if (chain == true){
      fill(0);
      text("C",pos.x + 5, pos.y + (s-5));
    }
  }
  
  void move(){
    if (pos.y == minH){
      coll = true;
    } else {
      coll = false;
    }
    if (coll == false){
      for (int i = 0; i < block.size(); i++){
        Block b = block.get(i);
        if (b.pos.y == pos.y - s && b.pos.x == pos.x){
          coll = true;
          break;
        }
        else {
          coll = false;
        }
      }// block size
    }
    if (coll == true){moveSpd = 0;}
    if (coll == false){moveSpd = -1;}
    pos.y += moveSpd;
  }// move
}
1 Like

Apart from your question

This is a nice post, well formatted and well put. Also the code is nice, with the arraylist and the idea of for loop backward to remove destroyed cells. Well done!

I just read your code a bit, you got …x+s but no … x-s.

Not solving the problem but a remark.

Is it so that only 4 blocks are destroyed or is the process like a chain going over the entire field?

I mean when it’s a chain:

I observed that the red cell has in fact a red neighbor. So that check might be working correctly.

Maybe the issue is rather that you don’t control whether we have a connection to the initial clicked screen.

Intuitively you would start from the initial cell, check the 4 surrounding neighbors and then check from these 4 again and then etc. - this sounds recursively but can be done also with for loops.

It should start with block 1 that you clicked on move to block 2 if any around block 1 is same type then move on. Until the block can’t find a match in its neighbors. I’ll post a pic to show what I mean.screen
in the pic number 1 is where the click happened then it moves to 2 then 3. At 3 it should choose up or left then stop because none are left, right, up & down.

Ah, so it hits only one of the two randomly?

looking at the code. I think it checks right, up, then down. I should fix that, but it should choose one of them not both. I think it might do both because I didn’t break it. As can see on this one it went right then got stopped because no others.

1 Like

Yeah, okay, I see

Chrisir

But no use to go over the entire grid

Instead start a clicked cell and jump on and on…?

I don’t wanna click each cell just wanna click one then it deletes the others. I’m thinking of switching to boolean right, left, up down to make it more random, but still id get why the adjacent one got chose.

I mean this:

But no use to go over the entire grid

Instead start a mouse clicked cell and then the program jumps on and on…?

but don’t i still need to get the number of the block?

That’s true, I forgot about this…

But I am not happy with the architecture

(I read this code only briefly, so apologies for any mistakes)

For example you call checked from draw() but is this necessary every time draw() runs? Wouldn’t it be enough to call it in mousePressed() when a change happened?

Also, you for-loop over the grid inside the class of one block/cell. In my opinion that is not clean code. Because one cell should not access the grid it belongs to (outside the class). Instead it should only take care of itself.

The grid stuff should be in functions outside the class (you could make a class grid though, but it’s not necessary).

I am not entirely sure about this; we should check. There are examples when a cell checks the grid but they are very specific.

Regards

Chrisir

1 Like

Yes, that’s in mousePressed(); but I mean in the class Block
in checked()

class Spawner

What is the purpose of class Spawner please?

Mainly the animation at start of the Sketch?

yes spawner spawns the blocks when bock.size don’t equal the amount i want. Checked checks to see if mouse is colliding with the block, so no it can’t be in mousePressed I need to know which block i’m over.

1 Like

I agree 100% with crisir about the architecture.
Actually gave it a try, and made it somewhat scaleble…convoluted code.

With the obvious

      if (b.pos.y == pos.y && b.pos.x == pos.x + s && b.chain == false ||
              b.pos.y == pos.y - s && b.pos.x == pos.x && b.chain == false ||
              b.pos.y == pos.y + s && b.pos.x == pos.x && b.chain == false ||
              b.pos.y == pos.y  && b.pos.x == pos.x - s && b.chain == false){
   

and displaying chainN it is

1 Like

Couldn’t help playing around with it, results on Github