I'm out of ideas and need help. So far I generate a board nicely using a flood fill algorithm and a 2d-array, I can also move tiles around the board.
Each Tile knows its own row, column and ID (images get set depending on ID, it's also what I use to check for matches).
The version I have for checking matches right now **almost** works, but it does not remove Tiles correctly if the match happens on row/col that got changed because of the recent move (tiles above that move down because of the match that was made from my move).
I have a lot of code but Ill try to explain it:
I check for matches in my game loop, so each frame I loop through the 8x8 board and check for matches. To check for matches I have these methods:
private void checkIfUpMatch(int row, int col){ //recursive
Tile toCheck = array[row][col];
toCheck.setChecked(true); //we set the tile as checked
if(toCheck.getRow() >= 7){ //if next row doesnt exist
return;
}
if(array[row + 1][col].getId() == array[row][col].getId()) {
verticalMatches ++;
checkIfUpMatch((toCheck.getRow() + 1), toCheck.getCol());
}
return;
}
private void checkIfDownMatch(int row, int col){ //recursive
Tile toCheck = array[row][col];
toCheck.setChecked(true);
if(toCheck.getRow() <= 0){ //if next row doesnt exist
return;
}
if(array[row - 1][col].getId() == array[row][col].getId()) {
verticalMatches ++;
checkIfDownMatch((toCheck.getRow() - 1), toCheck.getCol());
}
return;
}
private void checkIfLeftMatch(int row, int col){ //recursive
Tile toCheck = array[row][col];
toCheck.setChecked(true);
if(toCheck.getCol() <= 0){ //if next col doesnt exist
return;
}
if(array[row][col - 1].getId() == array[row][col].getId()) {
horizontalMatches ++;
checkIfLeftMatch((toCheck.getRow()), toCheck.getCol() - 1);
}
return;
}
private void checkIfRightMatch(int row, int col){ //recursive
Tile toCheck = array[row][col];
toCheck.setChecked(true);
if(toCheck.getCol() >= 7){ //if next col doesnt exist
return;
}
if(array[row][col + 1].getId() == array[row][col].getId()){
horizontalMatches ++;
checkIfRightMatch((toCheck.getRow()), toCheck.getCol() + 1);
}
return;
}
All of these methods do the same thing, just for up/down/left/right. Basically:
- Set the tile as checked
- If the tile is on the board and the neighboring tile matches, increase verticalMatches/horizontalMatches.
- call method again for next Tile (recursive)
I call these methods inside my `checkForMatch` method that is called in the game loop:
private void checkIfMatch(int row, int col){
checkIfUpMatch(row, col);
checkIfDownMatch(row, col);
checkIfLeftMatch(row, col);
checkIfRightMatch(row, col);
if(verticalMatches >= 3 || horizontalMatches >= 3){
for(int i=0; i<ROWS;i++){
for(int j = 0; j < COLS; j++){
if(array[i][j].isChecked()){
array[i][j].setMatched(true);
}
}
}
reFill();
}else{
for(int i=0; i<ROWS;i++){
for(int j = 0; j < COLS; j++){
if(array[i][j].isChecked() && !array[i][j].isMatched()){
array[i][j].setChecked(false);
}
}
}
}
verticalMatches = 1;
horizontalMatches = 1;
}
- If verticalMatches or horizontalMatches >= 3 we set the checked tiles as `matched`
- else we set `checked` back to false for all the tiles and reset verticalMatches/horizontalMatches
As you can see I call refill after we set all the tiles needed as `matched`, which looks like this:
private void reFill(){ //refill the board after a match has been made
for(int i=0; i<ROWS;i++){
for(int j = 0; j < COLS; j++){
if(array[i][j].isMatched()){
fallDown(i, j);
array[i][j].setMatched(false);
array[i][j].setChecked(false);
}
}
}
}
private void fallDown(int row, int col){ //replaces the ID of the removed tile from above
Tile removedTile = array[row][col];
if(row+verticalMatches > 7){
//we are at the top so just put in new tiles
int random = MathUtils.random(1, TILETYPES);
array[row][col].setId(random);
return;
}
Tile changeTile = array[row + verticalMatches][col]; //use vertical matches to set the removed tile to the correct ID
removedTile.setId(changeTile.getId());
fallDown(changeTile.getRow(), changeTile.getCol());
return;
}
- Here we loop through all the matched tiles and call `fallDown`
- `fallDown` replaces the removed tile with the tile above recursively until we are at the top of the board, then we insert new random tiles
That is it, any advice, tips or ideas are welcome, I've spent probably a good 20 hours of coding trying to figure this out. Maybe there is some easier way to do this that I am missing, or maybe I'm just making a few mistakes.
**EDIT:**
Trying to implement Shiro's solution:
private Array<Tile> matchedTiles = new Array<Tile>();
//...
private void checkVertical(int row, int col){
Tile toCheck = array[row][col];
matchedTiles.add(toCheck);
if(toCheck.getRow() < 7 && array[row + 1][col] == array[row][col]){ //check 1 up
matchedTiles.add(array[row + 1][col]);
}
if(toCheck.getRow() < 6 && array[row + 2][col] == array[row][col]){//check 2 up
matchedTiles.add(array[row + 2][col]);
}
if(toCheck.getRow() > 0 && array[row - 1][col] == array[row][col]){//check 1 down
matchedTiles.add(array[row - 1][col]);
}
if(toCheck.getRow() > 1 && array[row - 2][col] == array[row][col]){//check 2 down
matchedTiles.add(array[row - 2][col]);
}
if(matchedTiles.size >= 3){ //if we find a match
for(Tile t : matchedTiles){
array[t.getRow()][t.getCol()].setId(8); //actual array of tiles on board
}
matchedTiles = new Array<Tile>();
}else{
matchedTiles = new Array<Tile>();
}
}