你的位置:首页 > 操作系统

[操作系统]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<Point> myWhiteArray = new ArrayList<Point>(); //白棋子位置信息17   private List<Point> myBlackArray = new ArrayList<Point>(); //黑棋子位置信息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/460     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<Point> 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<Point> 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<Point> 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<Point> 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<Point> 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   //自定义接口,用于显示dialog7   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<Point> myWhiteArray = new ArrayList<Point>(); //白棋子位置信息 33   private List<Point> myBlackArray = new ArrayList<Point>(); //黑棋子位置信息 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/4130     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<Point> 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<Point> 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<Point> 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<Point> 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<Point> 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       @Override19       public void onClick(DialogInterface dialogInterface, int which) {20         MainActivity.this.finish();21       }22     });23     builder.setPositiveButton("再来一局", new OnClickListener() {24       25       @Override26       public void onClick(DialogInterface interface1, int which) {27         28         panel.restartGame();29       }30     });31     panel.setOnGameListener(new Chess_Panel.onGameListener() {32       33       @Override34       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.
 1 <RelativeLayout ="http://schemas.android.com/apk/res/android" 2   ="http://schemas.android.com/tools" 3   android:layout_width="match_parent" 4   android:layout_height="match_parent" 5   android:background="@drawable/bg" 6   tools:context="com.example.fivechess.MainActivity" > 7  8   <com.example.fivechess.Chess_Panel 9     android:id="@+id/main_panel"10     android:layout_width="match_parent"11     android:layout_height="match_parent"12     android:layout_centerInParent="true" />13 14 </RelativeLayout>

   至此,我们的项目就完成了,接下来解释下载安装到手机上运行了,其效果如下: