码迷,mamicode.com
首页 > 移动开发 > 详细

Android学习之旅:五子棋

时间:2016-07-30 21:07:37      阅读:315      评论:0      收藏:0      [点我收藏+]

标签:

  在学完了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>

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

技术分享

技术分享

 技术分享

Android学习之旅:五子棋

标签:

原文地址:http://www.cnblogs.com/jaycelgb/p/5721661.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!