編輯:關於Android編程
在學完了Android的基礎之後,我開始嘗試著寫一些小項目練練手,同時進一步鞏固自己的基礎知識,而我選的的第一個項目就是做一個簡單的人人對戰的五子棋小游戲。
首先,我們要新建一個自定義控件類Panel,這基本上涵蓋著整個項目的大部分操作,比如棋盤的設計等等,下面開始Panel的編寫,代碼如下:
1 public class Chess_Panel extends View{ 2 private int myPanelWidth ; //棋盤寬度 3 private float myLineHeight; //行寬 4 private int maxLine = 10; //行數 5 6 private Paint myPaint; //畫筆 7 private Bitmap myWhitePice; //白棋子 8 private Bitmap myBlackPice; //黑棋子 9 private float ratioPieceOfLineHight = 3 * 1.0f / 4; //棋子為行寬的3/4; 10 11 private boolean isGemOver; //游戲結束 12 public static int WHITE_WIN = 0; //勝利為白方標志 13 public static int BLACK_WIN = 1; //勝利為黑方標志 14 private boolean isWhite = true; //判斷是否是白棋先手,或當前為白棋下子 15 16 private ListmyWhiteArray = new ArrayList (); //白棋子位置信息 17 private List myBlackArray = new ArrayList (); //黑棋子位置信息 18 19 private onGameListener onGameListener; //回調接口 20 private int mUnder; //dialog的Y坐標 21 22 public Chess_Panel(Context context) { 23 this(context, null); 24 } 25 26 public Chess_Panel(Context context ,AttributeSet attributeSet){ //構造函數 27 super(context , attributeSet); 28 29 init(); 30 } 31 32 //初始化函數 33 private void init() { 34 myPaint = new Paint(); 35 myPaint.setColor(0X44ff0000); //給畫筆設置顏色 36 myPaint.setAntiAlias(true); //設置畫筆是否使用抗鋸齒 37 myPaint.setDither(true); //設置畫筆是否防抖動 38 myPaint.setStyle(Paint.Style.STROKE); //設置畫筆樣式,這裡使用描邊 39 40 myWhitePice = BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2); //設置棋子圖片 41 myBlackPice = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1); 42 43 } 44
所謂自定義控件(或稱組件)也就是編寫自己的控件類型,而非Android中提供的標准的控件。構造函數中,使用AttributeSet來完成控件類的構造函數。
Paint類:Android中的畫筆類,用於繪制圖形,它包含了很多方法對其屬性進行設置,如下:
setAntiAlias: 設置畫筆的鋸齒效果。
setColor: 設置畫筆顏色
setARGB: 設置畫筆的a,r,p,g值。
setAlpha: 設置Alpha值
setTextSize: 設置字體尺寸。
setStyle: 設置畫筆風格,空心或者實心。
setStrokeWidth: 設置空心的邊框寬度。
getColor: 得到畫筆的顏色
getAlpha: 得到畫筆的透明度。
Bitmap指的是一張位圖,而BitmapFactory是從文件,數據流,數組等的資源中生成一個Bitmap對象。 BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1)正是從資源中獲取一張圖片生成一個Bitmap對象的方法。當然,還有其他的方法可以用來生成Bitmap對象,這裡就不一一列舉了。
設置好畫筆屬性之後,我們就開始來設計我們的棋盤布局,以及棋盤的觸摸動作等,代碼如下:
1 //觸發動作 2 public boolean onTouchEvent(MotionEvent event){ 3 if (isGemOver) { 4 return false; 5 } 6 7 int action = event.getAction(); 8 if (action == MotionEvent.ACTION_UP) { //判斷觸摸動作,ACTION_UP為單點觸摸離開 9 int x = (int) event.getX(); 10 int y = (int) event.getY(); 11 Point p = getVaLidPiont(x,y); //獲取當前的坐標 12 13 if (myWhiteArray.contains(p)|| myBlackArray.contains(p)) { 14 return false; 15 } 16 17 if (isWhite) { 18 myWhiteArray.add(p); 19 }else { 20 myBlackArray.add(p); 21 } 22 invalidate(); //invalidate()是用來刷新View的,必須在UI線程中使用 23 isWhite = !isWhite; 24 } 25 return true; 26 } 27 28 29 private Point getVaLidPiont(int x , int y){ 30 return new Point((int)(x/myLineHeight),(int)(y/myLineHeight)); 31 } 32 33 //計算布局大小 34 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 35 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 36 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 37 38 int widthSize = MeasureSpec.getSize(widthMeasureSpec); 39 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 40 41 int width = Math.min(widthSize, heightSize); 42 43 if (widthMode == MeasureSpec.UNSPECIFIED) { //MeasureSpec.UNSPECIFIED表示未知大小 44 width = heightSize; 45 }else if (heightMode == MeasureSpec.UNSPECIFIED) { 46 width = widthSize; 47 } 48 49 setMeasuredDimension(width, width); 50 51 } 52 53 protected void onSizeChanged(int w, int h ,int oldw , int oldh) { //當View大小發生改變的時候會被系統自動回調 54 super.onSizeChanged(w, h, oldw, oldh); 55 myPanelWidth = w; 56 myLineHeight = myPanelWidth*1.0f/maxLine; 57 mUnder = h - (h - myPanelWidth) / 2; 58 59 int pieceWidth = (int) (myLineHeight*ratioPieceOfLineHight); //棋子大小占行寬的3/4 60 myWhitePice = Bitmap.createScaledBitmap(myWhitePice, pieceWidth, pieceWidth, false); //以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。 61 myBlackPice = Bitmap.createScaledBitmap(myBlackPice, pieceWidth, pieceWidth, false); 62 }
要學好android觸控,就要先了解MotionEvent,同時要對所用的MotionEvent常用的API要比較深入的了解。掌握MotionEvent事件是自定義控件中一個十分重要的部分。
事件的主要動作類型有如下幾種:
public static final int ACTION_DOWN = 0;單點觸摸動作
public static final int ACTION_UP = 1;單點觸摸離開動作
public static final int ACTION_MOVE = 2;觸摸點移動動作
public static final int ACTION_CANCEL = 3;觸摸動作取消
public static final int ACTION_OUTSIDE = 4;觸摸動作超出邊界
public static final int ACTION_POINTER_DOWN = 5;多點觸摸動作
public static final int ACTION_POINTER_UP = 6;多點離開動作
以下是一些非touch事件
public static final int ACTION_HOVER_MOVE = 7;
public static final int ACTION_SCROLL = 8;
public static final int ACTION_HOVER_ENTER = 9;
public static final int ACTION_HOVER_EXIT = 10;
onMeasure()函數由包含這個View的具體的ViewGroup調用, onMeasure()當控件的父元素正要放置該控件時調用.onMesure向父元素中傳入兩個參數——widthMeasureSpec和heightMeasureSpec,這兩個參數是由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同決定,其中包含了Size和Mode信息。
widthMeasureSpec和heightMeasureSpec的讀取如下:
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
pecMode一共有三種可能:
MeasureSpec.EXACTLY:父視圖希望子視圖的大小應該是specSize中指定的。
MeasureSpec.AT_MOST:子視圖的大小最多是specSize中指定的值,也就是說不建議子視圖的大小超過specSize中給定的值。
MeasureSpec.UNSPECIFIED:我們可以隨意指定視圖的大小。
onSizeChanged(int w, int h ,int oldw , int oldh):當View大小發生改變(比如分辨率變化)的時候會被系統自動回調。
Bitmap.createScaledBitmap(src,float, float, false) :以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。 接下來就開始設計棋盤線,代碼如下:
1 protected void onDraw(Canvas canvas) { //Canvas類相當於一塊畫布 2 super.onDraw(canvas); 3 drawBroad(canvas); 4 drawPiece(canvas); 5 checkGameOver(); 6 } 7 8 private void drawBroad(Canvas canvas){ //畫出棋盤線 9 int w = myPanelWidth; 10 float lineHeight = myLineHeight; 11 int startX = (int) (lineHeight/2); //棋盤線起始X坐標 12 int endX = (int)(w-lineHeight/2); //棋盤終止X坐標 13 for(int i = 0; i< maxLine; i++){ 14 int y = (int)((i+1.5)*lineHeight); //y坐標 15 16 canvas.drawLine(startX, y, endX, y, myPaint); //畫棋盤橫向線 17 canvas.drawLine(y, startX, y, endX, myPaint); //畫棋盤縱向線 18 } 19 } 20 21 //畫棋子 22 private void drawPiece(Canvas canvas) { 23 int n1 = myWhiteArray.size(); 24 int n2 = myBlackArray.size(); 25 for(int i =0; i< n1 ;i++){ 26 Point whitePoint = myWhiteArray.get(i); 27 canvas.drawBitmap(myWhitePice, (whitePoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight, 28 (whitePoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null); 29 //drawBitmap(Bitmap bitmap, float left, float top, Paint paint);Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置 30 } 31 32 for(int i =0; i< n2 ;i++){ 33 Point blackPoint = myBlackArray.get(i); 34 canvas.drawBitmap(myBlackPice, (blackPoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight, 35 (blackPoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null); 36 } 37 }
在Android中,Canvas類相當於畫布,另外它也是顯示位圖(Bitmap類)的核心類,它的屬性方法如下:
Canvas(): 創建一個空的畫布,可以使用setBitmap()方法來設置繪制具體的畫布。
Canvas(Bitmap bitmap): 以bitmap對象創建一個畫布,則將內容都繪制在bitmap上,因此bitmap不得為null。
Canvas(GL gl): 在繪制3D效果時使用,與OpenGL相關。
drawColor: 設置Canvas的背景顏色。
setBitmap: 設置具體畫布。
clipRect: 設置顯示區域,即設置裁剪區。 isOpaque:檢測是否支持透明。 rotate: 旋轉畫布 translate:移動畫布 scale:縮放畫布
setViewport: 設置畫布中顯示窗口。
skew: 設置偏移量。 restore: 用來恢復上一次save之前的狀態 save:用來保存Canvas的當前狀態
注意: save方法、restore方法一般是成對出現的,save方法可多於restore方法,但restore方法不能多於save方法
drawBitmap(Bitmap bitmap, float left, float top, Paint paint) Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置,panit為我們設計的畫筆
接下來的就是游戲中的一些判斷動作了:
1 //檢測游戲是否結束 2 private void checkGameOver(){ 3 boolean whiteWin = checkFiveInLine(myWhiteArray); 4 boolean blackWin = checkFiveInLine(myBlackArray); 5 6 if (whiteWin || blackWin) { 7 isGemOver = true; 8 if (onGameListener != null) { 9 onGameListener.onGameOver(whiteWin ? WHITE_WIN : BLACK_WIN); 10 } 11 } 12 } 13 //回調一個int數據用於設置Dialog的位置 14 public int getUnder() { 15 16 return mUnder; 17 } 18 19 //檢測是否存在五棋子相連的情況 20 private boolean checkFiveInLine(ListmyArray){ 21 for(Point p : myArray){ 22 int x = p.x; 23 int y = p.y; 24 25 boolean win_flag = //判斷是否存在五子相連情況 26 checkHorizontal(x , y ,myArray)||checkVertical(x,y,myArray) 27 ||checkLeftDiagonal(x,y,myArray)||checkRightDiagonal(x,y,myArray); 28 if (win_flag) { 29 return true; 30 } 31 } 32 return false; 33 } 34 35 //橫向檢查是否滿足五子相連 36 private boolean checkHorizontal(int x ,int y ,List myArray){ 37 int count = 1; 38 for(int i = 1;i < 5; i++){ 39 if (myArray.contains(new Point(x+i,y))) { 40 count++; 41 }else { 42 break; 43 } 44 } 45 if (count == 5) { 46 return true; 47 } 48 for(int i = 1;i < 5; i++){ 49 if (myArray.contains(new Point(x-i,y))) { 50 count++; 51 }else { 52 break; 53 } 54 55 56 if (count == 5) { 57 return true; 58 } 59 } 60 return false; 61 } 62 63 //縱向檢查是否滿足五子相連 64 private boolean checkVertical(int x ,int y ,List myArray){ 65 int count = 1; 66 for(int i = 1;i < 5; i++){ 67 if (myArray.contains(new Point(x,y+i))) { 68 count++; 69 }else { 70 break; 71 } 72 73 } 74 if (count == 5) { 75 return true; 76 } 77 for(int i = 1;i < 5; i++){ 78 if (myArray.contains(new Point(x,y-i))) { 79 count++; 80 }else { 81 break; 82 } 83 if (count == 5) { 84 return true; 85 } 86 } 87 return false; 88 } 89 90 //左斜向檢查是否滿足五子相連 91 private boolean checkLeftDiagonal(int x ,int y ,List myArray){ 92 int count = 1; 93 for(int i = 1;i < 5; i++){ 94 if (myArray.contains(new Point(x-i,y+i))) { 95 count++; 96 }else { 97 break; 98 } 99 100 } 101 if (count == 5) { 102 return true; 103 } 104 for(int i = 1;i < 5; i++){ 105 if (myArray.contains(new Point(x+i,y-i))) { 106 count++; 107 }else { 108 break; 109 } 110 if (count == 5) { 111 return true; 112 } 113 } 114 return false; 115 } 116 117 //右斜向檢查是否滿足五子相連 118 private boolean checkRightDiagonal(int x ,int y ,List myArray){ 119 int count = 1; 120 for(int i = 1;i < 5; i++){ //切記,i = 1 開始,否則就會只檢測到三個子相連就結束了 121 if (myArray.contains(new Point(x-i,y-i))) { 122 count++; 123 }else { 124 break; 125 } 126 } 127 if (count == 5) { 128 return true; 129 } 130 for(int i = 1;i < 5; i++){ 131 if (myArray.contains(new Point(x+i,y+i))) { 132 count++; 133 }else { 134 break; 135 } 136 if (count == 5) { 137 return true; 138 } 139 } 140 return false; 141 } 142 143 //重新開始游戲 144 protected void restartGame(){ 145 myWhiteArray.clear(); 146 myBlackArray.clear(); 147 isGemOver = false; 148 isWhite = false; 149 invalidate(); //刷新 150 }
invalidate()是android中用於刷新View顯示的一個方法。
可以說重載onMeasure(),onLayout(),onDraw()三個函數構建了自定義View的外觀形象。再加上onTouchEvent()等重載視圖的行為,可以構建任何我們需要的可感知到的自定義View。
另外,我們還應該暴露我們自定義的控件的接口,以方便調用:
1 // 用於回調的接口 2 public interface onGameListener { 3 void onGameOver(int i); 4 } 5 6 //自定義接口,用於顯示dialog 7 public void setOnGameListener(Chess_Panel.onGameListener onGameListener) { 8 this.onGameListener = onGameListener; 9 }
那麼,完整的Chess_Panel代碼如下所示:
1 package com.example.fivechess; 2 3 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import android.content.Context; 8 import android.graphics.Bitmap; 9 import android.graphics.BitmapFactory; 10 import android.graphics.Canvas; 11 import android.graphics.Paint; 12 import android.graphics.Point; 13 import android.util.AttributeSet; 14 import android.view.MotionEvent; 15 import android.view.View; 16 17 public class Chess_Panel extends View{ 18 private int myPanelWidth ; //棋盤寬度 19 private float myLineHeight; //行寬 20 private int maxLine = 10; //行數 21 22 private Paint myPaint; //畫筆 23 private Bitmap myWhitePice; //白棋子 24 private Bitmap myBlackPice; //黑棋子 25 private float ratioPieceOfLineHight = 3 * 1.0f / 4; //棋子為行寬的3/4; 26 27 private boolean isGemOver; //游戲結束 28 public static int WHITE_WIN = 0; //勝利為白方標志 29 public static int BLACK_WIN = 1; //勝利為黑方標志 30 private boolean isWhite = true; //判斷是否是白棋先手,或當前為白棋下子 31 32 private ListmyWhiteArray = new ArrayList (); //白棋子位置信息 33 private List myBlackArray = new ArrayList (); //黑棋子位置信息 34 35 private onGameListener onGameListener; //回調接口 36 private int mUnder; //dialog的Y坐標 37 38 public Chess_Panel(Context context) { 39 this(context, null); 40 } 41 42 public Chess_Panel(Context context ,AttributeSet attributeSet){ //構造函數 43 super(context , attributeSet); 44 45 init(); 46 } 47 48 // 用於回調的接口 49 public interface onGameListener { 50 void onGameOver(int i); 51 } 52 53 //自定義接口,用於顯示dialog 54 public void setOnGameListener(Chess_Panel.onGameListener onGameListener) { 55 this.onGameListener = onGameListener; 56 } 57 58 //初始化函數 59 private void init() { 60 myPaint = new Paint(); 61 myPaint.setColor(0X44ff0000); //給畫筆設置顏色 62 myPaint.setAntiAlias(true); //設置畫筆是否使用抗鋸齒 63 myPaint.setDither(true); //設置畫筆是否防抖動 64 myPaint.setStyle(Paint.Style.STROKE); //設置畫筆樣式,這裡使用描邊 65 66 myWhitePice = BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2); //設置棋子圖片 67 myBlackPice = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1); 68 69 } 70 71 //觸發事件 72 public boolean onTouchEvent(MotionEvent event){ 73 if (isGemOver) { 74 return false; 75 } 76 77 int action = event.getAction(); 78 if (action == MotionEvent.ACTION_UP) { //判斷觸摸動作,ACTION_UP為單點觸摸離開 79 int x = (int) event.getX(); 80 int y = (int) event.getY(); 81 Point p = getVaLidPiont(x,y); 82 83 if (myWhiteArray.contains(p)|| myBlackArray.contains(p)) { 84 return false; 85 } 86 87 if (isWhite) { 88 myWhiteArray.add(p); 89 }else { 90 myBlackArray.add(p); 91 } 92 invalidate(); //invalidate()是用來刷新View的,必須在UI線程中使用 93 isWhite = !isWhite; 94 } 95 return true; 96 } 97 98 99 private Point getVaLidPiont(int x , int y){ 100 return new Point((int)(x/myLineHeight),(int)(y/myLineHeight)); 101 } 102 103 //計算布局大小 104 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 105 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 106 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 107 108 int widthSize = MeasureSpec.getSize(widthMeasureSpec); 109 int heightSize = MeasureSpec.getSize(heightMeasureSpec); 110 111 int width = Math.min(widthSize, heightSize); 112 113 if (widthMode == MeasureSpec.UNSPECIFIED) { //MeasureSpec.UNSPECIFIED表示未知大小 114 width = heightSize; 115 }else if (heightMode == MeasureSpec.UNSPECIFIED) { 116 width = widthSize; 117 } 118 119 setMeasuredDimension(width, width); 120 121 } 122 123 protected void onSizeChanged(int w, int h ,int oldw , int oldh) { //當View大小發生改變的時候會被系統自動回調 124 super.onSizeChanged(w, h, oldw, oldh); 125 myPanelWidth = w; 126 myLineHeight = myPanelWidth*1.0f/maxLine; 127 mUnder = h - (h - myPanelWidth) / 2; 128 129 int pieceWidth = (int) (myLineHeight*ratioPieceOfLineHight); //棋子大小占行寬的3/4 130 myWhitePice = Bitmap.createScaledBitmap(myWhitePice, pieceWidth, pieceWidth, false); //以src為原圖,創建新的圖像,指定新圖像的高寬以及是否可變。 131 myBlackPice = Bitmap.createScaledBitmap(myBlackPice, pieceWidth, pieceWidth, false); 132 } 133 134 protected void onDraw(Canvas canvas) { //Canvas類相當於一塊畫布 135 super.onDraw(canvas); 136 drawBroad(canvas); 137 drawPiece(canvas); 138 checkGameOver(); 139 } 140 141 private void drawBroad(Canvas canvas){ //畫出棋盤線 142 int w = myPanelWidth; 143 float lineHeight = myLineHeight; 144 int startX = (int) (lineHeight/2); //棋盤線起始X坐標 145 int endX = (int)(w-lineHeight/2); //棋盤終止X坐標 146 for(int i = 0; i< maxLine; i++){ 147 int y = (int)((i+1.5)*lineHeight); //y坐標 148 149 canvas.drawLine(startX, y, endX, y, myPaint); //畫棋盤橫向線 150 canvas.drawLine(y, startX, y, endX, myPaint); //畫棋盤縱向線 151 } 152 } 153 154 //畫棋子 155 private void drawPiece(Canvas canvas) { 156 int n1 = myWhiteArray.size(); 157 int n2 = myBlackArray.size(); 158 for(int i =0; i< n1 ;i++){ 159 Point whitePoint = myWhiteArray.get(i); 160 canvas.drawBitmap(myWhitePice, (whitePoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight, 161 (whitePoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null); 162 //drawBitmap(Bitmap bitmap, float left, float top, Paint paint);Bitmap:圖片對象,left:偏移左邊的位置,top: 偏移頂部的位置 163 } 164 165 for(int i =0; i< n2 ;i++){ 166 Point blackPoint = myBlackArray.get(i); 167 canvas.drawBitmap(myBlackPice, (blackPoint.x+(1-ratioPieceOfLineHight)/2)*myLineHeight, 168 (blackPoint.y+(1-ratioPieceOfLineHight)/2)*myLineHeight, null); 169 } 170 } 171 172 //檢測游戲是否結束 173 private void checkGameOver(){ 174 boolean whiteWin = checkFiveInLine(myWhiteArray); 175 boolean blackWin = checkFiveInLine(myBlackArray); 176 177 if (whiteWin || blackWin) { 178 isGemOver = true; 179 if (onGameListener != null) { 180 onGameListener.onGameOver(whiteWin ? WHITE_WIN : BLACK_WIN); 181 } 182 } 183 } 184 //回調一個int數據用於設置Dialog的位置 185 public int getUnder() { 186 187 return mUnder; 188 } 189 190 //檢測是否存在五棋子相連的情況 191 private boolean checkFiveInLine(List myArray){ 192 for(Point p : myArray){ 193 int x = p.x; 194 int y = p.y; 195 196 boolean win_flag = //判斷是否存在五子相連情況 197 checkHorizontal(x , y ,myArray)||checkVertical(x,y,myArray) 198 ||checkLeftDiagonal(x,y,myArray)||checkRightDiagonal(x,y,myArray); 199 if (win_flag) { 200 return true; 201 } 202 } 203 return false; 204 } 205 206 //橫向檢查是否滿足五子相連 207 private boolean checkHorizontal(int x ,int y ,List myArray){ 208 int count = 1; 209 for(int i = 1;i < 5; i++){ 210 if (myArray.contains(new Point(x+i,y))) { 211 count++; 212 }else { 213 break; 214 } 215 } 216 if (count == 5) { 217 return true; 218 } 219 for(int i = 1;i < 5; i++){ 220 if (myArray.contains(new Point(x-i,y))) { 221 count++; 222 }else { 223 break; 224 } 225 226 227 if (count == 5) { 228 return true; 229 } 230 } 231 return false; 232 } 233 234 //縱向檢查是否滿足五子相連 235 private boolean checkVertical(int x ,int y ,List myArray){ 236 int count = 1; 237 for(int i = 1;i < 5; i++){ 238 if (myArray.contains(new Point(x,y+i))) { 239 count++; 240 }else { 241 break; 242 } 243 244 } 245 if (count == 5) { 246 return true; 247 } 248 for(int i = 1;i < 5; i++){ 249 if (myArray.contains(new Point(x,y-i))) { 250 count++; 251 }else { 252 break; 253 } 254 if (count == 5) { 255 return true; 256 } 257 } 258 return false; 259 } 260 261 //左斜向檢查是否滿足五子相連 262 private boolean checkLeftDiagonal(int x ,int y ,List myArray){ 263 int count = 1; 264 for(int i = 1;i < 5; i++){ 265 if (myArray.contains(new Point(x-i,y+i))) { 266 count++; 267 }else { 268 break; 269 } 270 271 } 272 if (count == 5) { 273 return true; 274 } 275 for(int i = 1;i < 5; i++){ 276 if (myArray.contains(new Point(x+i,y-i))) { 277 count++; 278 }else { 279 break; 280 } 281 if (count == 5) { 282 return true; 283 } 284 } 285 return false; 286 } 287 288 //右斜向檢查是否滿足五子相連 289 private boolean checkRightDiagonal(int x ,int y ,List myArray){ 290 int count = 1; 291 for(int i = 1;i < 5; i++){ //切記,i = 1 開始,否則就會只檢測到三個子相連就結束了 292 if (myArray.contains(new Point(x-i,y-i))) { 293 count++; 294 }else { 295 break; 296 } 297 } 298 if (count == 5) { 299 return true; 300 } 301 for(int i = 1;i < 5; i++){ 302 if (myArray.contains(new Point(x+i,y+i))) { 303 count++; 304 }else { 305 break; 306 } 307 if (count == 5) { 308 return true; 309 } 310 } 311 return false; 312 } 313 314 //重新開始游戲 315 protected void restartGame(){ 316 myWhiteArray.clear(); 317 myBlackArray.clear(); 318 isGemOver = false; 319 isWhite = false; 320 invalidate(); 321 } 322 }
終於,完成我們的自定義控件設計之後,我們就進入Activity的編寫吧,代碼如下:
1 public class MainActivity extends Activity { 2 3 private Chess_Panel panel; 4 private AlertDialog.Builder builder; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.activity_main); 10 11 Window window = getWindow(); 12 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 13 panel = (Chess_Panel)findViewById(R.id.main_panel); 14 builder= new AlertDialog.Builder(MainActivity.this); 15 builder.setTitle("游戲結束"); 16 builder.setNegativeButton("退出", new OnClickListener() { 17 18 @Override 19 public void onClick(DialogInterface dialogInterface, int which) { 20 MainActivity.this.finish(); 21 } 22 }); 23 builder.setPositiveButton("再來一局", new OnClickListener() { 24 25 @Override 26 public void onClick(DialogInterface interface1, int which) { 27 28 panel.restartGame(); 29 } 30 }); 31 panel.setOnGameListener(new Chess_Panel.onGameListener() { 32 33 @Override 34 public void onGameOver(int i) { 35 String str = ""; 36 if (i== Chess_Panel.WHITE_WIN) { 37 str = "白方勝利!"; 38 }else if (i== Chess_Panel.BLACK_WIN) { 39 str = "黑方勝利!"; 40 } 41 builder.setMessage(str); 42 builder.setCancelable(false); //不可用返回鍵取消 43 AlertDialog dialog = builder.create(); 44 Window dialogWindow = dialog.getWindow(); 45 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 46 params.x = 0; 47 params.y = panel.getUnder(); 48 dialogWindow.setAttributes(params); //設置Dialog顯示的位置 49 dialog.setCanceledOnTouchOutside(false); //不可點擊取消 50 dialog.show(); 51 } 52 } ); 53 54 } 55 }
這兩句的作用是讓游戲滿屏顯示,即不顯示通知狀態欄: Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
另外注意,不要忘記在activity_main.xml中添加我們自定義的控件,代碼如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg" tools:context="com.example.fivechess.MainActivity" > <com.example.fivechess.Chess_Panel android:id="@+id/main_panel" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" /> </RelativeLayout>
至此,我們的項目就完成了,接下來解釋下載安裝到手機上運行了,其效果如下:
一、前言今天我們來看一下Android中一個眾人熟悉的一個屬性:shareUserId,關於這個屬性可能大家都很熟悉了,最近在開發項目,用到了這個屬性,雖然知道一點知識,
當我們在移動端閱讀文章時,總會有朋友發了一條微信給你。這時候,我是繼續看文章還是回微信呢?MIUI8的微信多窗口功能讓你徹底擺脫這個煩惱,多窗口模式能夠讓你
DrawerLayout組件同樣是V4包中的組件,也是直接繼承於ViewGroup類,所以這個類也是一個容器類。使用DrawerLayout可以輕松的實現抽屜效果,使用D
學習章節:第一章 Activity的生命周期和啟動模式學習內容:1正常情況下Activity的生命周期分析先上一張經典圖片鎮樓:測試正常情況Activity生命周期的代碼