最近由于项目需要学习了一下Android ,感觉汗不错。做了一个Android版的扫雷游戏。
游戏简介
在此游戏中,我们使用一个块的网格,其中有一些随机的地雷
下面是效果图
一、应用程序布局
使用TableLayout布局控件。设置3行。
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/back"> <TableRow> <TextView android:id="@+id/timer" android:layout_column="0" android:layout_width="fill_parent" android:layout_height="48px" android:gravity="center_horizontal" android:padding="5dip" android:textColor="#FFFFFF" android:textSize="35sp" android:text=" 0" /> <ImageButton android:id="@+id/smiley" android:layout_column="1" android:scaleType="center" android:padding="5dip" android:layout_width="48px" android:background="@drawable/smiley_button_states" android:layout_height="48px" /> <TextView android:id="@+id/minecount" android:layout_column="2" android:layout_width="fill_parent" android:layout_height="48px" android:gravity="center_horizontal" android:padding="5dip" android:textColor="#FFFFFF" android:textSize="35sp" android:text="000" /> </TableRow> <TableRow> <TextView android:layout_column="0" android:layout_height="50px" android:layout_width="fill_parent" android:layout_span="3" android:padding="10dip" /> </TableRow> <TableRow> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/minefield" android:layout_width="260px" android:layout_height="260px" android:gravity="bottom" android:stretchColumns="*" android:layout_span="3" android:padding="5dip"> </TableLayout> </TableRow> </TableLayout>
二、地雷块
Block.java
/** * 地雷的块,继承自Button * @author 记忆的永恒 * */ public class Block extends Button { private boolean isCovered; // 块是否覆盖 private boolean isMined; // 下个块 private boolean isFlagged; // 是否将该块标记为一个潜在的地雷 private boolean isQuestionMarked; // 是否是块的问题标记 private boolean isClickable; // 是否可以单击 private int numberOfMinesInSurrounding; // 在附近的地雷数量块 public Block(Context context) { super(context); // TODO Auto-generated constructor stub } public Block(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public Block(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 设置默认参数 */ public void setDefaults() { isCovered = true; isMined = false; isFlagged = false; isQuestionMarked = false; isClickable = true; numberOfMinesInSurrounding = 0; this.setBackgroundResource(R.drawable.square_blue); setBoldFont(); } public void setNumberOfSurroundingMines(int number) { this.setBackgroundResource(R.drawable.square_grey); updateNumber(number); } public void setMineIcon(boolean enabled) { this.setText("M"); if (!enabled) { this.setBackgroundResource(R.drawable.square_grey); this.setTextColor(Color.RED); } else { this.setTextColor(Color.BLACK); } } public void setFlagIcon(boolean enabled) { this.setText("F"); if (!enabled) { this.setBackgroundResource(R.drawable.square_grey); this.setTextColor(Color.RED); } else { this.setTextColor(Color.BLACK); } } public void setQuestionMarkIcon(boolean enabled) { this.setText("?"); if (!enabled) { this.setBackgroundResource(R.drawable.square_grey); this.setTextColor(Color.RED); } else { this.setTextColor(Color.BLACK); } } public void setBlockAsDisabled(boolean enabled) { if (!enabled) { this.setBackgroundResource(R.drawable.square_grey); } else { this.setTextColor(R.drawable.square_blue); } } public void clearAllIcons() { this.setText(""); } private void setBoldFont() { this.setTypeface(null, Typeface.BOLD); } public void OpenBlock() { if (!isCovered) { return; } setBlockAsDisabled(false); isCovered = false; if (hasMine()) { setMineIcon(false); } else { setNumberOfSurroundingMines(numberOfMinesInSurrounding); } } public void updateNumber(int text) { if (text != 0) { this.setText(Integer.toString(text)); switch (text) { case 1: this.setTextColor(Color.BLUE); break; case 2: this.setTextColor(Color.rgb(0, 100, 0)); break; case 3: this.setTextColor(Color.RED); break; case 4: this.setTextColor(Color.rgb(85, 26, 139)); break; case 5: this.setTextColor(Color.rgb(139, 28, 98)); break; case 6: this.setTextColor(Color.rgb(238, 173, 14)); break; case 7: this.setTextColor(Color.rgb(47, 79, 79)); break; case 8: this.setTextColor(Color.rgb(71, 71, 71)); break; case 9: this.setTextColor(Color.rgb(205, 205, 0)); break; } } } public void plantMine() { isMined = true; } public void triggerMine() { setMineIcon(true); this.setTextColor(Color.RED); } public boolean isCovered() { return isCovered; } public boolean hasMine() { return isMined; } public void setNumberOfMinesInSurrounding(int number) { numberOfMinesInSurrounding = number; } public int getNumberOfMinesInSorrounding() { return numberOfMinesInSurrounding; } public boolean isFlagged() { return isFlagged; } public void setFlagged(boolean flagged) { isFlagged = flagged; } public boolean isQuestionMarked() { return isQuestionMarked; } public void setQuestionMarked(boolean questionMarked) { isQuestionMarked = questionMarked; } public boolean isClickable() { return isClickable; } public void setClickable(boolean clickable) { isClickable = clickable; } } 三、主界面 1.TableLayout动态添加行 mineField = (TableLayout)findViewById(R.id.MineField); private void showMineField() { for (int row = 1; row < numberOfRowsInMineField + 1; row++) { TableRow tableRow = new TableRow(this); tableRow.setLayoutParams(new LayoutParams((blockDimension + 2 * blockPadding) * numberOfColumnsInMineField, blockDimension + 2 * blockPadding)); for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { blocks[row][column].setLayoutParams(new LayoutParams( blockDimension + 2 * blockPadding, blockDimension + 2 * blockPadding)); blocks[row][column].setPadding(blockPadding, blockPadding, blockPadding, blockPadding); tableRow.addView(blocks[row][column]); } mineField.addView(tableRow,new TableLayout.LayoutParams( (blockDimension + 2 * blockPadding) * numberOfColumnsInMineField, blockDimension + 2 * blockPadding)); } }
2.定时器Handler
private Handler timer = new Handler(); private int secondsPassed = 0; public void startTimer(){ if (secondsPassed == 0) { timer.removeCallbacks(updateTimeElasped); // tell timer to run call back after 1 second timer.postDelayed(updateTimeElasped, 1000); } } public void stopTimer() { // disable call backs timer.removeCallbacks(updateTimeElasped); } // timer call back when timer is ticked private Runnable updateTimeElasped = new Runnable() { public void run() { long currentMilliseconds = System.currentTimeMillis(); ++secondsPassed; txtTimer.setText(Integer.toString(secondsPassed)); // add notification timer.postAtTime(this, currentMilliseconds); // notify to call back after 1 seconds // basically to remain in the timer loop timer.postDelayed(updateTimeElasped, 1000); } }; 3.第一次点击 private boolean isTimerStarted; // check if timer already started or not blocks[row][column].setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // start timer on first click if (!isTimerStarted) { startTimer(); isTimerStarted = true; } ... } });
4.第一次点击无雷
private boolean areMinesSet; // check if mines are planted in blocks blocks[row][column].setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { ... // set mines on first click if (!areMinesSet) { areMinesSet = true; setMines(currentRow, currentColumn); } } }); private void setMines(int currentRow, int currentColumn) { // set mines excluding the location where user clicked Random rand = new Random(); int mineRow, mineColumn; for (int row = 0; row < totalNumberOfMines; row++) { mineRow = rand.nextInt(numberOfColumnsInMineField); mineColumn = rand.nextInt(numberOfRowsInMineField); if ((mineRow + 1 != currentColumn) || (mineColumn + 1 != currentRow)) { if (blocks[mineColumn + 1][mineRow + 1].hasMine()) { row--; // mine is already there, don't repeat for same block } // plant mine at this location blocks[mineColumn + 1][mineRow + 1].plantMine(); } // exclude the user clicked location else { row--; } } int nearByMineCount; // count number of mines in surrounding blocks ... }
5.点击雷块的效果
private void rippleUncover(int rowClicked, int columnClicked) { // don't open flagged or mined rows if (blocks[rowClicked][columnClicked].hasMine() || blocks[rowClicked][columnClicked].isFlagged()) { return; } // open clicked block blocks[rowClicked][columnClicked].OpenBlock(); // if clicked block have nearby mines then don't open further if (blocks[rowClicked][columnClicked].getNumberOfMinesInSorrounding() != 0 ) { return; } // open next 3 rows and 3 columns recursively for (int row = 0; row < 3; row++) { for (int column = 0; column < 3; column++) { // check all the above checked conditions // if met then open subsequent blocks if (blocks[rowClicked + row - 1][columnClicked + column - 1].isCovered() && (rowClicked + row - 1 > 0) && (columnClicked + column - 1 > 0) && (rowClicked + row - 1 < numberOfRowsInMineField + 1) && (columnClicked + column - 1 < numberOfColumnsInMineField + 1)) { rippleUncover(rowClicked + row - 1, columnClicked + column - 1 ); } } } return; }
6.以问好标记空白
blocks[row][column].setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View view) { // simulate a left-right (middle) click // if it is a long click on an opened mine then // open all surrounding blocks ... // if clicked block is enabled, clickable or flagged if (blocks[currentRow][currentColumn].isClickable() && (blocks[currentRow][currentColumn].isEnabled() || blocks[currentRow][currentColumn].isFlagged())) { // for long clicks set: // 1. empty blocks to flagged // 2. flagged to question mark // 3. question mark to blank // case 1. set blank block to flagged if (!blocks[currentRow][currentColumn].isFlagged() && !blocks[currentRow][currentColumn].isQuestionMarked()) { blocks[currentRow][currentColumn].setBlockAsDisabled(false); blocks[currentRow][currentColumn].setFlagIcon(true); blocks[currentRow][currentColumn].setFlagged(true); minesToFind--; //reduce mine count updateMineCountDisplay(); } // case 2. set flagged to question mark else if (!blocks[currentRow][currentColumn].isQuestionMarked()) { blocks[currentRow][currentColumn].setBlockAsDisabled(true); blocks[currentRow][currentColumn].setQuestionMarkIcon(true); blocks[currentRow][currentColumn].setFlagged(false); blocks[currentRow][currentColumn].setQuestionMarked(true); minesToFind++; // increase mine count updateMineCountDisplay(); } // case 3. change to blank square else { blocks[currentRow][currentColumn].setBlockAsDisabled(true); blocks[currentRow][currentColumn].clearAllIcons(); blocks[currentRow][currentColumn].setQuestionMarked(false); // if it is flagged then increment mine count if (blocks[currentRow][currentColumn].isFlagged()) { minesToFind++; // increase mine count updateMineCountDisplay(); } // remove flagged status blocks[currentRow][currentColumn].setFlagged(false); } updateMineCountDisplay(); // update mine display } return true; } });
7.记录胜负
// check status of the game at each step if (blocks[currentRow + previousRow][currentColumn + previousColumn].hasMine()) { // oops game over finishGame(currentRow + previousRow, currentColumn + previousColumn); } // did we win the game if (checkGameWin()) { // mark game as win winGame(); } private boolean checkGameWin() { for (int row = 1; row < numberOfRowsInMineField + 1; row++) { for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { if (!blocks[row][column].hasMine() && blocks[row][column].isCovered()) { return false; } } } return true; }
8.完整代码
MinesweeperGame.java package com.VertexVerveInc.Games; import java.util.Random; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; import android.widget.TableRow.LayoutParams; public class MinesweeperGame extends Activity { private TextView txtMineCount; private TextView txtTimer; private ImageButton btnSmile; private TableLayout mineField; private Block blocks[][]; // blocks for mine field private int blockDimension = 24; // width of each block private int blockPadding = 2; // padding between blocks private int numberOfRowsInMineField = 9; private int numberOfColumnsInMineField = 9; private int totalNumberOfMines = 10; // timer to keep track of time elapsed private Handler timer = new Handler(); private int secondsPassed = 0; private boolean isTimerStarted; // check if timer already started or not private boolean areMinesSet; // check if mines are planted in blocks private boolean isGameOver; private int minesToFind; // number of mines yet to be discovered /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test); txtMineCount = (TextView) findViewById(R.id.minecount); txtTimer = (TextView) findViewById(R.id.timer); btnSmile = (ImageButton) findViewById(R.id.smiley); btnSmile.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { endExistingGame(); startNewGame(); } }); mineField = (TableLayout)findViewById(R.id.minefield); showDialog("Click smiley to start New Game", 2000, true, false); } private void startNewGame() { createMineField(); // display all blocks in UI showMineField(); minesToFind = totalNumberOfMines; isGameOver = false; secondsPassed = 0; } private void createMineField() { // we take one row extra row for each side // overall two extra rows and two extra columns // first and last row/column are used for calculations purposes only // x|xxxxxxxxxxxxxx|x // ------------------ // x| |x // x| |x // ------------------ // x|xxxxxxxxxxxxxx|x // the row and columns marked as x are just used to keep counts of near // by mines blocks = new Block[numberOfRowsInMineField + 2][numberOfColumnsInMineField + 2]; for (int row = 0; row < numberOfColumnsInMineField + 2; row++) { for (int column = 0; column < numberOfColumnsInMineField + 2; column++) { blocks[row][column] = new Block(this); blocks[row][column].setDefaults(); // pass current row and column number as final int's to event // listeners // this way we can ensure that each event listener is associated // to // particular instance of block only final int currentRow = row; final int currentColumn = column; blocks[row][column].setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // start timer on first click if (!isTimerStarted) { startTimer(); isTimerStarted = true; } // set mines on first click if (!areMinesSet) { areMinesSet = true; setMines(currentRow, currentColumn); } // this is not first click // check if current block is flagged // if flagged the don't do anything // as that operation is handled by LongClick // if block is not flagged then uncover nearby blocks // till we get numbered mines if (!blocks[currentRow][currentColumn].isFlagged()) { // open nearby blocks till we get numbered blocks rippleUncover(currentRow, currentColumn); // did we clicked a mine if (blocks[currentRow][currentColumn].hasMine()) { // Oops, game over finishGame(currentRow, currentColumn); } // check if we win the game if (checkGameWin()) { // mark game as win winGame(); } } } }); // add Long Click listener // this is treated as right mouse click listener blocks[row][column] .setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View view) { // simulate a left-right (middle) click // if it is a long click on an opened mine then // open all surrounding blocks if (!blocks[currentRow][currentColumn] .isCovered() && (blocks[currentRow][currentColumn] .getNumberOfMinesInSorrounding() > 0) && !isGameOver) { int nearbyFlaggedBlocks = 0; for (int previousRow = -1; previousRow < 2; previousRow++) { for (int previousColumn = -1; previousColumn < 2; previousColumn++) { if (blocks[currentRow + previousRow][currentColumn + previousColumn] .isFlagged()) { nearbyFlaggedBlocks++; } } } // if flagged block count is equal to nearby // mine count // then open nearby blocks if (nearbyFlaggedBlocks == blocks[currentRow][currentColumn] .getNumberOfMinesInSorrounding()) { for (int previousRow = -1; previousRow < 2; previousRow++) { for (int previousColumn = -1; previousColumn < 2; previousColumn++) { // don't open flagged blocks if (!blocks[currentRow + previousRow][currentColumn + previousColumn] .isFlagged()) { // open blocks till we get // numbered block rippleUncover( currentRow + previousRow, currentColumn + previousColumn); // did we clicked a mine if (blocks[currentRow + previousRow][currentColumn + previousColumn] .hasMine()) { // oops game over finishGame( currentRow + previousRow, currentColumn + previousColumn); } // did we win the game if (checkGameWin()) { // mark game as win winGame(); } } } } } // as we no longer want to judge this // gesture so return // not returning from here will actually // trigger other action // which can be marking as a flag or // question mark or blank return true; } // if clicked block is enabled, clickable or // flagged if (blocks[currentRow][currentColumn] .isClickable() && (blocks[currentRow][currentColumn] .isEnabled() || blocks[currentRow][currentColumn] .isFlagged())) { // for long clicks set: // 1. empty blocks to flagged // 2. flagged to question mark // 3. question mark to blank // case 1. set blank block to flagged if (!blocks[currentRow][currentColumn] .isFlagged() && !blocks[currentRow][currentColumn] .isQuestionMarked()) { blocks[currentRow][currentColumn] .setBlockAsDisabled(false); blocks[currentRow][currentColumn] .setFlagIcon(true); blocks[currentRow][currentColumn] .setFlagged(true); minesToFind--; // reduce mine count updateMineCountDisplay(); } // case 2. set flagged to question mark else if (!blocks[currentRow][currentColumn] .isQuestionMarked()) { blocks[currentRow][currentColumn] .setBlockAsDisabled(true); blocks[currentRow][currentColumn] .setQuestionMarkIcon(true); blocks[currentRow][currentColumn] .setFlagged(false); blocks[currentRow][currentColumn] .setQuestionMarked(true); minesToFind++; // increase mine count updateMineCountDisplay(); } // case 3. change to blank square else { blocks[currentRow][currentColumn] .setBlockAsDisabled(true); blocks[currentRow][currentColumn] .clearAllIcons(); blocks[currentRow][currentColumn] .setQuestionMarked(false); // if it is flagged then increment mine // count if (blocks[currentRow][currentColumn] .isFlagged()) { minesToFind++; // increase mine // count updateMineCountDisplay(); } // remove flagged status blocks[currentRow][currentColumn] .setFlagged(false); } updateMineCountDisplay(); // update mine // display } return true; } }); } } } private void showMineField() { for (int row = 1; row < numberOfRowsInMineField + 1; row++) { TableRow tableRow = new TableRow(this); tableRow.setLayoutParams(new LayoutParams( (blockDimension + 2 * blockPadding) * numberOfColumnsInMineField, blockDimension + 2 * blockPadding)); for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { blocks[row][column].setLayoutParams(new LayoutParams( blockDimension + 2 * blockPadding, blockDimension + 2 * blockPadding)); blocks[row][column].setPadding(blockPadding, blockPadding, blockPadding, blockPadding); tableRow.addView(blocks[row][column]); } mineField.addView(tableRow, new TableLayout.LayoutParams( (blockDimension + 2 * blockPadding) * numberOfColumnsInMineField, blockDimension + 2 * blockPadding)); } } private void endExistingGame() { stopTimer(); // stop if timer is running txtTimer.setText("000"); // revert all text txtMineCount.setText("000"); // revert mines count btnSmile.setBackgroundResource(R.drawable.smile); // remove all rows from mineField TableLayout mineField.removeAllViews(); // set all variables to support end of game isTimerStarted = false; areMinesSet = false; isGameOver = false; minesToFind = 0; } private boolean checkGameWin() { for (int row = 1; row < numberOfRowsInMineField + 1; row++) { for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { if (!blocks[row][column].hasMine() && blocks[row][column].isCovered()) { return false; } } } return true; } private void updateMineCountDisplay() { if (minesToFind < 0) { txtMineCount.setText(Integer.toString(minesToFind)); } else if (minesToFind < 10) { txtMineCount.setText("00" + Integer.toString(minesToFind)); } else if (minesToFind < 100) { txtMineCount.setText("0" + Integer.toString(minesToFind)); } else { txtMineCount.setText(Integer.toString(minesToFind)); } } private void winGame() { stopTimer(); isTimerStarted = false; isGameOver = true; minesToFind = 0; // set mine count to 0 // set icon to cool dude btnSmile.setBackgroundResource(R.drawable.cool); updateMineCountDisplay(); // update mine count // disable all buttons // set flagged all un-flagged blocks for (int row = 1; row < numberOfRowsInMineField + 1; row++) { for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { blocks[row][column].setClickable(false); if (blocks[row][column].hasMine()) { blocks[row][column].setBlockAsDisabled(false); blocks[row][column].setFlagIcon(true); } } } // show message showDialog("You won in " + Integer.toString(secondsPassed) + " seconds!", 1000, false, true); } private void finishGame(int currentRow, int currentColumn) { isGameOver = true; // mark game as over stopTimer(); // stop timer isTimerStarted = false; btnSmile.setBackgroundResource(R.drawable.sad); // show all mines // disable all blocks for (int row = 1; row < numberOfRowsInMineField + 1; row++) { for (int column = 1; column < numberOfColumnsInMineField + 1; column++) { // disable block blocks[row][column].setBlockAsDisabled(false); // block has mine and is not flagged if (blocks[row][column].hasMine() && !blocks[row][column].isFlagged()) { // set mine icon blocks[row][column].setMineIcon(false); } // block is flagged and doesn't not have mine if (!blocks[row][column].hasMine() && blocks[row][column].isFlagged()) { // set flag icon blocks[row][column].setFlagIcon(false); } // block is flagged if (blocks[row][column].isFlagged()) { // disable the block blocks[row][column].setClickable(false); } } } // trigger mine blocks[currentRow][currentColumn].triggerMine(); // show message showDialog("You tried for " + Integer.toString(secondsPassed) + " seconds!", 1000, false, false); } private void setMines(int currentRow, int currentColumn) { // set mines excluding the location where user clicked Random rand = new Random(); int mineRow, mineColumn; for (int row = 0; row < totalNumberOfMines; row++) { mineRow = rand.nextInt(numberOfColumnsInMineField); mineColumn = rand.nextInt(numberOfRowsInMineField); if ((mineRow + 1 != currentColumn) || (mineColumn + 1 != currentRow)) { if (blocks[mineColumn + 1][mineRow + 1].hasMine()) { row--; // mine is already there, don't repeat for same block } // plant mine at this location blocks[mineColumn + 1][mineRow + 1].plantMine(); } // exclude the user clicked location else { row--; } } int nearByMineCount; for (int row = 0; row < numberOfRowsInMineField + 2; row++) { for (int column = 0; column < numberOfColumnsInMineField + 2; column++) { // for each block find nearby mine count nearByMineCount = 0; if ((row != 0) && (row != (numberOfRowsInMineField + 1)) && (column != 0) && (column != (numberOfColumnsInMineField + 1))) { // check in all nearby blocks for (int previousRow = -1; previousRow < 2; previousRow++) { for (int previousColumn = -1; previousColumn < 2; previousColumn++) { if (blocks[row + previousRow][column + previousColumn].hasMine()) { // a mine was found so increment the counter nearByMineCount++; } } } blocks[row][column] .setNumberOfMinesInSurrounding(nearByMineCount); } // for side rows (0th and last row/column) // set count as 9 and mark it as opened else { blocks[row][column].setNumberOfMinesInSurrounding(9); blocks[row][column].OpenBlock(); } } } } private void rippleUncover(int rowClicked, int columnClicked) { // don't open flagged or mined rows if (blocks[rowClicked][columnClicked].hasMine() || blocks[rowClicked][columnClicked].isFlagged()) { return; } // open clicked block blocks[rowClicked][columnClicked].OpenBlock(); // if clicked block have nearby mines then don't open further if (blocks[rowClicked][columnClicked].getNumberOfMinesInSorrounding() != 0) { return; } // open next 3 rows and 3 columns recursively for (int row = 0; row < 3; row++) { for (int column = 0; column < 3; column++) { // check all the above checked conditions // if met then open subsequent blocks if (blocks[rowClicked + row - 1][columnClicked + column - 1] .isCovered() && (rowClicked + row - 1 > 0) && (columnClicked + column - 1 > 0) && (rowClicked + row - 1 < numberOfRowsInMineField + 1) && (columnClicked + column - 1 < numberOfColumnsInMineField + 1)) { rippleUncover(rowClicked + row - 1, columnClicked + column - 1); } } } return; } public void startTimer() { if (secondsPassed == 0) { timer.removeCallbacks(updateTimeElasped); // tell timer to run call back after 1 second timer.postDelayed(updateTimeElasped, 1000); Log.i("tag",String.valueOf((timer.postDelayed(updateTimeElasped, 1000))) ); } } public void stopTimer() { // disable call backs timer.removeCallbacks(updateTimeElasped); } // timer call back when timer is ticked private Runnable updateTimeElasped = new Runnable() { public void run() { long currentMilliseconds = System.currentTimeMillis(); ++secondsPassed; txtTimer.setText(Integer.toString(secondsPassed)); // add notification timer.postAtTime(this, currentMilliseconds); // notify to call back after 1 seconds // basically to remain in the timer loop timer.postDelayed(updateTimeElasped, 1000); } }; private void showDialog(String message, int milliseconds, boolean useSmileImage, boolean useCoolImage) { // show message Toast dialog = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG); dialog.setGravity(Gravity.CENTER, 0, 0); LinearLayout dialogView = (LinearLayout) dialog.getView(); ImageView coolImage = new ImageView(getApplicationContext()); if (useSmileImage) { coolImage.setImageResource(R.drawable.smile); } else if (useCoolImage) { coolImage.setImageResource(R.drawable.cool); } else { coolImage.setImageResource(R.drawable.sad); } dialogView.addView(coolImage, 0); dialog.setDuration(milliseconds); dialog.show(); Log.i("tag", "showDialog()"); } }