Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習之旅:五子棋

Android學習之旅:五子棋

編輯:關於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 List myWhiteArray = 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(List myArray){
 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 List myWhiteArray = 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>

至此,我們的項目就完成了,接下來解釋下載安裝到手機上運行了,其效果如下:

 

\

 

 

\

 

 

\
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved