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 void checkVertical(int row, int col){
// The current id of the tile that we are checking for matches
final int currentId = tiles[row][col].getId();
// The matches of the current tile
final List<Tile> matchedTiles = new ArrayList<Tile>();
matchedTiles.add(tiles[row][col]);
if(row < 7 && tiles[row + 1][col].getId() == currentId){ // 1 up
matchedTiles.add(tiles[row + 1][col]);
if(row < 6 && tiles[row + 2][col].getId() == currentId) // 2 up
matchedTiles.add(tiles[row + 2][col]);
}
if(row > 0 && tiles[row - 1][col].getId() == currentId) { // 1 down
matchedTiles.add(tiles[row - 1][col]);
if(row > 1 && tiles[row - 2][col].getId() == currentId) // 2 down
matchedTiles.add(tiles[row - 2][col]);
}
// If we find a match
if(matchedTiles.size >= 3) {
for(Tile tile : matchedTiles) {
final int row = tile.getRow();
final int col = tile.getCol();
tiles[row][col].setId(8);
}
}
}
tile.setChecked(true)
first thing, means that even if the tile is in the middle, it is marked as checked and will be removed. And I agree that the code is infefficient at parts but this is usually how I write code, I just want to make it work first, then I worry about optimization after \$\endgroup\$ – Green_qaue Sep 6 '15 at 22:38fallDown()
method \$\endgroup\$ – Green_qaue Sep 6 '15 at 23:03fallDown()
animation has ended. You might wanna introduce a variableisFalling
and not include the tiles withisFalling == true
when checking for "matches" \$\endgroup\$ – dimitris93 Sep 6 '15 at 23:08