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/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<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      //自定义接口,用于显示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<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/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<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             @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中添加我们自定义的控件,代码如下:
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="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>

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

时间: 2024-08-11 03:38:21

Android学习之旅:五子棋的相关文章

我的Android学习之旅

去年大概在七月份的时候误打误撞接触了一阵子Android,之后由于工作时间比较忙,无暇顾及,九月份的时候自己空闲的时间比较多,公司相对来说加班情况没以前严重.开启了个人的Android学习之旅,初衷是想将Android的博客做个索引文章的,不过想想还可以分享一些学习中的历程,算是对自己的Android学习 有个交代吧.由于在公司有工作,学习的时间通常就是周一到周五晚上的时间和周末时间,周一到周五晚上的时间不确定,因此牺牲了大量的周末时间来学习Android,有点像苦行僧,时间段持续了三个多月.如

菜鸟的Android学习之旅(一)

最近在拜读郭霖老师的经典<第一行代码>,作为一名菜鸟级的新手来说这本书确实对新手很友好,讲的很详细.如果你也像我一样作为一只小菜鸟想学习Android,还不了解这本书的,还没有想好入手哪一本书作为自己新手启蒙书的同学,个人觉得你就不要徘徊了,加入购物车吧! 因为我才是刚开始学习不久,第二章才学习了很少一部分,所以我没办法说点有营养的东西,我就先记录一下我学习过程中经历的错误吧. 第二章开始,郭老师教我们如何手动创建活动.边看书边敲代码,但是你会发现当你完全按照书上所说敲完所有需要的代码之后代码

Android学习之旅--Android Studio

一.开发工具了解 Android Studio 是一个Android集成开发工具,基于IntelliJ IDEA. 类似 Eclipse ADT,提供了集成的 Android 开发工具用于开发和调试.2013年5月16日,在I/O大会上,谷歌推出新的Android开发环境--Android Studio,并对开发者控制台进行了改进,增加了五个新的功能:优化小贴士.应用翻译服务.推荐跟踪.营收曲线图.用版测试和阶段性展示.起初的几个版本并不受到开发者的好评,各种BUG出现,所以人们普遍还是接受Ec

Android学习之旅--简易音乐播放器实现之前期准备

学习Android有两个月了,感觉现在进入一个瓶颈--基础知识了解,但是不能灵活运用.我想这是所有新手学习android时都会遇到的 问题,所以打算做一个简易音乐播放器的小项目,这也是特别适合新手的练习项目.虽然小,但是也能考察不少东西.前几天看到一句话-----编 程不仅是一种知识,更是一种技能.既然是技能,那就需要不断练习才能熟练掌握. 项目目标前期实现本地音乐的播放,后期会往网络音乐方面发展,如果进行顺利的话,我会将源码放在github上,欢迎各位大神指导^- ^.我会坚持每天一更,记录每

My Android 学习之旅--开始

其实,很早就想写写博客了,一直懒到现在. 学习android也不是今天才开始的,大概在2月份过完年之后就开始了,买了我认为还可以的书<Android从入门到精通>,花了不到一个月的时间,把前面的基础部分看完了,但是还是感觉啥都不知道,为啥呢?因为对它太陌生,太不了解了. 自己当初是学了C#+.netFramework,动手做了一个项目,总结出来一句话:原来语言是相通的.所以在当今,工作越来越不好找,就决定找个热门的行业,手机来作为自己以后跳槽的方向,最初的目的是为了自己以后好找一份工作. 算了

Android的资源类型和存储方式简介-android学习之旅(五十二)

android资源的类型 android资源的存储方式

Android回调事件传播-android学习之旅(四十五)

概念简介 代码演示 package peng.liu.test; import android.app.ActionBar; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.Display; import android.view.KeyEvent; import

Android日历视图(CalendarView)讲解-android学习之旅(三十六)

CalendarView简介 CalendarView用于显示和选择日期,如果希望监听事件的改变可以用setOnDateChangeListener()方法. CalendarView属性介绍 代码示例 package peng.liu.test; import android.app.Activity; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bund

Android的加速度传感器模拟摇一摇的效果-android学习之旅(66)

主要介绍一下android的加速传感器的简单用法,模拟摇一摇 ,如果x,y,z三个方向的加速度超过了15,就会弹出Toast,当然你可以设置更复杂的策略,比如判断间隔 代码如下 public class MainActivity extends Activity { private SensorManager sensorManager; private TextView textView; @Override protected void onCreate(Bundle savedInstan