标签:
在学完了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>
至此,我们的项目就完成了,接下来解释下载安装到手机上运行了,其效果如下:
标签:
原文地址:http://www.cnblogs.com/jaycelgb/p/5721661.html