扫雷游戏

MineSweeper是一个不错的Android开源扫雷游戏,对于初学Android开发网的网友可能有很大的帮助,对于Java游戏开发也有一定的参考意义。该游戏主要有以下技术值得学习:

  1. 个性化字体,计分器使用的是LED字体,可以帮助我们如何导入外部字体在Android平台中显示。

  2. 带图片的Toast,下面的You won in 36 seconds这个Toast使用了自定义的布局,可以显示图片和文字。

  3. 自定义Button控件,可以看到标记是否为雷,显示附近地雷数量的按钮控件,初学者可以很容易的学习到Android开发中常用的自定义控件技术。
 
  4.  因为游戏实时性不高,这里没有用到SurfaceView,下次Android开发网给大家提供一个将对高级些的例子。
扫雷游戏
关键代码如下:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:stretchColumns="0,2"
    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="40sp"
			android:text="000" />
			
		<ImageButton android:id="@+id/Smiley"
			android:layout_column="1"
			android:background="@drawable/smiley_button_states"
			android:scaleType="center"
			android:padding="5dip" 
			android:layout_width="48px"
			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="40sp"
			android:text="000" />
    </TableRow>
    
	<TableRow>
		<TextView
			android:layout_column="0"
			android:layout_width="fill_parent"
			android:layout_height="50px"
			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>

smiley_button_states.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" 
    	  android:state_pressed="false" 
    	  android:layout_width="48px"
    	  android:layout_height="48px"
    	  android:drawable="@drawable/smile" />
    	  
    <item android:state_focused="true" 
    	  android:state_pressed="true"
    	  android:layout_width="48px"
    	  android:layout_height="48px"
    	  android:drawable="@drawable/surprise" />
    	  
    <item android:state_focused="false" 
    	  android:state_pressed="true"
    	  android:layout_width="48px"
    	  android:layout_height="48px"
	      android:drawable="@drawable/surprise" />
	      
    <item android:layout_width="48px"
     	  android:layout_height="48px"
    	  android:drawable="@drawable/smile" />
</selector>

Block.java
package com.VertexVerveInc.Games;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.Button;

public class Block extends Button
{
	private boolean isCovered; // is block covered yet
	private boolean isMined; // does the block has a mine underneath
	private boolean isFlagged; // is block flagged as a potential mine
	private boolean isQuestionMarked; // is block question marked
	private boolean isClickable; // can block accept click events
	private int numberOfMinesInSurrounding; // number of mines in nearby blocks

	public Block(Context context)
	{
		super(context);
	}

	public Block(Context context, AttributeSet attrs)
	{
		super(context, attrs);
	}

	public Block(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
	}

	// set default properties for the block
	public void setDefaults()
	{
		isCovered = true;
		isMined = false;
		isFlagged = false;
		isQuestionMarked = false;
		isClickable = true;
		numberOfMinesInSurrounding = 0;

		this.setBackgroundResource(R.drawable.square_blue);
		setBoldFont();
	}

	// mark the block as disabled/opened
	// update the number of nearby mines
	public void setNumberOfSurroundingMines(int number)
	{
		this.setBackgroundResource(R.drawable.square_grey);
		
		updateNumber(number);
	}

	// set mine icon for block
	// set block as disabled/opened if false is passed
	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);
		}
	}

	// set mine as flagged
	// set block as disabled/opened if false is passed
	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);
		}
	}

	// set mine as question mark
	// set block as disabled/opened if false is passed
	public void setQuestionMarkIcon(boolean enabled)
	{
		this.setText("?");
		
		if (!enabled)
		{
			this.setBackgroundResource(R.drawable.square_grey);
			this.setTextColor(Color.RED);
		}
		else
		{
			this.setTextColor(Color.BLACK);
		}
	}

	// set block as disabled/opened if false is passed
	// else enable/close it
	public void setBlockAsDisabled(boolean enabled)
	{
		if (!enabled)
		{
			this.setBackgroundResource(R.drawable.square_grey);
		}
		else
		{
			this.setBackgroundResource(R.drawable.square_blue);
		}
	}

	// clear all icons/text
	public void clearAllIcons()
	{
		this.setText("");
	}

	// set font as bold
	private void setBoldFont()
	{
		this.setTypeface(null, Typeface.BOLD);
	}

	// uncover this block
	public void OpenBlock()
	{
		// cannot uncover a mine which is not covered
		if (!isCovered)
			return;

		setBlockAsDisabled(false);
		isCovered = false;

		// check if it has mine
		if (hasMine())
		{
			setMineIcon(false);
		}
		// update with the nearby mine count
		else
		{
			setNumberOfSurroundingMines(numberOfMinesInSurrounding);
		}
	}

	// set text as nearby mine count
	public void updateNumber(int text)
	{
		if (text != 0)
		{
			this.setText(Integer.toString(text));

			// select different color for each number
			// we have already skipped 0 mine count
			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;
			}
		}
	}

	// set block as a mine underneath
	public void plantMine()
	{
		isMined = true;
	}

	// mine was opened
	// change the block icon and color
	public void triggerMine()
	{
		setMineIcon(true);
		this.setTextColor(Color.RED);
	}

	// is block still covered
	public boolean isCovered()
	{
		return isCovered;
	}

	// does the block have any mine underneath
	public boolean hasMine()
	{
		return isMined;
	}

	// set number of nearby mines
	public void setNumberOfMinesInSurrounding(int number)
	{
		numberOfMinesInSurrounding = number;
	}

	// get number of nearby mines
	public int getNumberOfMinesInSorrounding()
	{
		return numberOfMinesInSurrounding;
	}

	// is block marked as flagged
	public boolean isFlagged()
	{
		return isFlagged;
	}

	// mark block as flagged
	public void setFlagged(boolean flagged)
	{
		isFlagged = flagged;
	}

	// is block marked as a question mark
	public boolean isQuestionMarked()
	{
		return isQuestionMarked;
	}

	// set question mark for the block
	public void setQuestionMarked(boolean questionMarked)
	{
		isQuestionMarked = questionMarked;
	}

	// can block receive click event
	public boolean isClickable()
	{
		return isClickable;
	}

	// disable block for receive click events
	public void setClickable(boolean clickable)
	{
		isClickable = clickable;
	}
}

MinesweeperGame.java
package com.VertexVerveInc.Games;

import java.util.Random;

import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
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.TableRow.LayoutParams;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

public class MinesweeperGame extends Activity
{
	private TextView txtMineCount;
	private TextView txtTimer;
	private ImageButton btnSmile;

	private TableLayout mineField; // table layout to add mines to

	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

	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		txtMineCount = (TextView) findViewById(R.id.MineCount);
		txtTimer = (TextView) findViewById(R.id.Timer);
		
		// set font style for timer and mine count to LCD style
		Typeface lcdFont = Typeface.createFromAsset(getAssets(),
				"fonts/lcd2mono.ttf");
		txtMineCount.setTypeface(lcdFont);
		txtTimer.setTypeface(lcdFont);
		
		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()
	{
		// plant mines and do rest of the calculations
		createMineField();
		// display all blocks in UI
		showMineField();
		
		minesToFind = totalNumberOfMines;
		isGameOver = false;
		secondsPassed = 0;
	}

	private void showMineField()
	{
		// remember we will not show 0th and last Row and Columns
		// they are used for calculation purposes only
		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 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 < numberOfRowsInMineField + 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;

				// add Click Listener
				// this is treated as Left Mouse click
				blocks[row][column].setOnClickListener(new OnClickListener()
				{
					@Override
					public void onClick(View view)
					{
						// 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 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;

		// count number of mines in surrounding blocks 
		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);
		}
	}

	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;

			if (secondsPassed < 10)
			{
				txtTimer.setText("00" + Integer.toString(secondsPassed));
			}
			else if (secondsPassed < 100)
			{
				txtTimer.setText("0" + Integer.toString(secondsPassed));
			}
			else
			{
				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();
	}
}

你可能感兴趣的:(游戏,android,UI,OS,REST)