自定义View实践-一个简单的棋类游戏
来源:互联网 发布:那些淘宝店铺质量又好 编辑:程序博客网 时间:2024/06/05 07:06
原文发表在我的个人博客:http://kahn.wang/a-practice-of-custom-view-a-simple-chess/
最近看了慕课网上一个通过自定义View来实现五子棋游戏的视频,想起自己小时候经常跟小伙伴玩的一个棋类游戏,于是就自己动手,跟着视频把自己的想法实践了出来。也是作为自定义View的一个练习。
规则介绍
需求分析
要实现这样一个游戏我们需要解决以下的问题:
- 根据每个点处的状态绘制视图
- 棋子是可拖动的,并且拖动的时候棋子会放大,以模仿拿起的效果
- 如何判断输赢
- 判断落点是不是符合规则,比如不能一下走两格,不能走规定外的路径
- 判断该轮到哪一方走,另一方则无法移动视图。
- 能够重新开始,重置棋盘
如何绘制
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制棋盘 drawBoard(canvas); //绘制棋子 drawPieces(canvas); if (isMoving){ drawMovingPices(canvas); } }很简单,只有三个方法,首先是绘制棋盘,这个很简单就不再多说了,然后是根据每点状态绘制棋子,这个接下来说,然后判断是否在移动中,如果在移动中的话,绘制移动中的棋子。
绘制静止棋子
public static final int NO_PIECES=0; public static final int WHITE_PIECES=1; public static final int BLACK_PIECES=2; //是否是选中状态 public static final int SELECT_WHITE_PIECES=3; public static final int SELECT_BLACK_PIECES=4; private int[][] positionCondition={ {WHITE_PIECES,WHITE_PIECES,WHITE_PIECES}, {NO_PIECES,NO_PIECES,NO_PIECES}, {BLACK_PIECES,BLACK_PIECES,BLACK_PIECES} };
上面还有3和4,分别代表了被选择时的白棋和黑棋,在绘制时使其绘制放大的棋子。
然后就可以根据每个点的情况来绘制棋子了,这里给出绘制棋子的方法:
private void drawPieces(Canvas canvas) { float lineHeight=mLineHeight; //棋盘每格的高度 //开始绘制 //通过判断每个点是否有棋子 for (int i=0;i<=Max_LINE;i++) { for (int j=0;j<=Max_LINE;j++){ int x=(int)(lineHeight/4); int halfPiecesWidth= (int) (lineHeight*ratioPiecesOfLineHeight/2); int selectedHalfPiecesWidth= (int) (lineHeight*ratioSelectedPiecesOfLineheight/2); if (positionCondition[i][j]==WHITE_PIECES){ canvas.drawBitmap(mWhitePieces,x+j*lineHeight-halfPiecesWidth,x+i*lineHeight-halfPiecesWidth,null); }else if (positionCondition[i][j]==BLACK_PIECES){ canvas.drawBitmap(mBlackPieces,x+j*lineHeight-halfPiecesWidth,x+i*lineHeight-halfPiecesWidth,null); }else if (positionCondition[i][j]==SELECT_WHITE_PIECES){ canvas.drawBitmap(mSelectedWhitePieces,x+j*lineHeight-selectedHalfPiecesWidth,x+i*lineHeight-selectedHalfPiecesWidth,null); }else if (positionCondition[i][j]==SELECT_BLACK_PIECES){ canvas.drawBitmap(mSelectedBlackPieces,x+j*lineHeight-selectedHalfPiecesWidth,x+i*lineHeight-selectedHalfPiecesWidth,null); } } } }
绘制移动的棋子
private void drawMovingPices(Canvas canvas) { float selectedHalfPiecesWidth= mLineHeight*ratioSelectedPiecesOfLineheight/2; if (movingPieces==WHITE_PIECES){ canvas.drawBitmap(mSelectedWhitePieces,mPointF.x-selectedHalfPiecesWidth,mPointF.y-selectedHalfPiecesWidth,null); }else if (movingPieces==BLACK_PIECES){ canvas.drawBitmap(mSelectedBlackPieces,mPointF.x-selectedHalfPiecesWidth,mPointF.y-selectedHalfPiecesWidth,null); } }
其中mPointF.x和mPointF.y为触摸事件为MOVE时获得的坐标。
这样需求1和2得到解决。
输赢判断
private void checkIsGameOver() { boolean a=positionCondition[1][1]==positionCondition[0][0] &&positionCondition[1][1]==positionCondition[2][2]; boolean b=positionCondition[1][1]==positionCondition[0][1] &&positionCondition[1][1]==positionCondition[2][1]; boolean c=positionCondition[1][1]==positionCondition[0][2] &&positionCondition[1][1]==positionCondition[2][0]; boolean d=positionCondition[1][1]==positionCondition[1][0] &&positionCondition[1][1]==positionCondition[1][2]; if (a||b||c||d){ if (positionCondition[1][1]==WHITE_PIECES){ Toast.makeText(getContext(),R.string.white_goal,Toast.LENGTH_LONG).show(); }else if (positionCondition[1][1]==BLACK_PIECES){ Toast.makeText(getContext(),R.string.black_goal,Toast.LENGTH_LONG).show(); } }}
其中a、b、c、d代表胜利时的四个位置,当任何一个发生时,游戏结束。因为无论哪种位置都通过中点,所以只需要判断中点是哪一方,就能确定是哪一方胜利。
这样需求3就能够满足
规则外的判断
boolean judge=(upi+upj)%2!=0&&(downi+downj)%2!=0; //不能走在规定外的斜线 if (positionCondition[upj][upi]==NO_PIECES //落点必须没有棋子 &&Math.abs(upi-downi)<=1 //不能走两格以上 &&Math.abs(upj-downj)<=1 &&!judge //不能走规定外的斜线 &&Math.abs(upi-downi)+Math.abs(upj-downj)!=0 //不能原地不动 &&isMoving //确定移动了 ){ positionCondition[upj][upi]=movingPieces; mCounts=mCounts+1; //判断是哪个棋子先走 if (mCounts==1){ mFirst=movingPieces; } }else { //棋子回到原位 positionCondition[downj][downi]=movingPieces; }
其中upi和upj代表落点的位置,downi和downj代表起点的位置,因为对应到touch事件中的DOWN和UP。
其中对于该轮到哪个棋子走的判断,这里引入两个变量,一个mFirst,用来记录是哪个棋子先走的,一个mCounts,用来记录步数,两个初始值都为0,当每一步完成时,设置mCounts加1。上面代码中有这个判断,如果mCounts=1,即第一步完成时,就把第一步移动的棋子赋值给mFirst。
那么如何判断是否轮到呢,很简单,我们发现,如果已走的步数为偶数时,那么当前是轮到第一个走的一方移动棋子了,如果为奇数,则轮到另一方,具体代码如下:
//正在移动 if (mFirst==0 ||(mFirst==movingPieces&&mCounts%2==0) //是否轮到的条件,如果没轮到则不移动 ||(mFirst!=movingPieces&&mCounts%2==1)){ isMoving=true; }else { //如果不轮到走的话之前的要放大显示 positionCondition[downj][downi] =movingPieces+ 2; }
这个判断写在touch事件的MOVE事件中,如果不是轮到你而你点击了话,就相应放大该棋子但不作移动(isMoving为false).
至此需求4和需求5均得到满足,游戏就基本开发完成了。
重新开始
游戏结束后要重新开始,只需要将一开始的二维数组恢复初始值,并设置mFirst和mCounts为0就可以了。
这里写一个公共方法来响应actionBar上的重新开始操作:
//重新开始游戏 public void restartGame(){ for (int i=0;i<=Max_LINE;i++){ positionCondition[0][i]=WHITE_PIECES; } for (int i=0;i<=Max_LINE;i++){ positionCondition[1][i]=NO_PIECES; } for (int i=0;i<=Max_LINE;i++){ positionCondition[2][i]=BLACK_PIECES; } mFirst=0; mCounts=0; invalidate(); }
- 自定义View实践-一个简单的棋类游戏
- 一个棋类游戏统计连子个数的算法
- 自己设计的棋类游戏
- 一个简单的自定义VIEW的DEMO
- 一个简单的Android自定义view详解
- 简单实现一个自定义view的ProgressBar
- 一个简单的Android自定义View
- Android 实现一个简单的自定义View
- 棋类游戏
- 一个简单自定义View控件
- ios 棋类游戏对战的实现
- 简单的view 自定义
- 简单的自定义View
- 简单的自定义view
- 自定义RatingBar(自定义view的实践)
- 自定义View学习-绘制一个简单的圆
- 一个简单的自定义view(补间动画)
- 一个简单的自定义View,仿圆形进度条
- 阅读笔记1:fast tracking via spatio-temporal context learning
- Scala常见错误
- gdb调试
- 日常笔记之事件驱动
- 我的Android知识架构
- 自定义View实践-一个简单的棋类游戏
- 软件工程(十七)
- EditText小知识
- C++第5次上机实验
- Windows7操作记录_操作时间记录_启动时间记录_日志查看
- gdb调试
- javascript之prototype原型属性
- Eclipse之保存自动格式化代码
- Vector相关简单操作