安卓五子棋小游戏

一款五子棋小游戏,可以拿来联系一下自定义View             Demo源码下载:   源码   (studio上面构建的项目,导入时要配置一下gradle文件)

1.写一个类继承View

/*** Created by fanday on 2016/4/23.*/
public class PieceView extends View {private int lineNum=10;//棋盘的行列数private float lineHeight;//每一行的行高private int width;//棋盘的边长(棋盘是正方形的)private Paint paint;public PieceView(Context context) {this(context,null);//一个参数的构造调用两个的,最终都走三个参数的构造}public PieceView(Context context, AttributeSet attrs) {this(context, attrs,0);}public PieceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();//构造方法中需要初始化的变量}

2.在构造方法中调用初始化方法,初始化一些变量

   private Bitmap whitePiece;//白棋private Bitmap blackPiece;//黑棋private double intScale=0.75;//棋子显示到棋盘上面是以棋盘的网格大小为基准的,棋子的缩放比例private Paint piecePaint;//画棋子的画笔对象private void init() {piecePaint=new Paint(Paint.ANTI_ALIAS_FLAG);paint=new Paint();//画网格的画笔对象paint.setAntiAlias(true);paint.setColor(0xffff0000);paint.setStyle(Paint.Style.STROKE);//设置画笔只描边this.setBackgroundColor(0x44aaaaaa);whitePiece= BitmapFactory.decodeResource(getResources(), R.drawable.white);blackPiece=BitmapFactory.decodeResource(getResources(),R.drawable.black);}

3.在onMeasure()方法中对View的宽高测量模式进行判断

  @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int widthSize=MeasureSpec.getSize(widthMeasureSpec);//获取宽度的sixeint widthMode = MeasureSpec.getMode(widthMeasureSpec);//获取宽度的Modeint heightSize=MeasureSpec.getSize(heightMeasureSpec);int heightMode=MeasureSpec.getMode(heightMeasureSpec);if(widthMode==MeasureSpec.UNSPECIFIED){//如果宽度的测量模式不确定,就让宽度=高度widthSize=heightSize;}else if(heightMode==MeasureSpec.UNSPECIFIED){//若果高度的测量模式不确定的,就让宽度=宽度widthSize=widthSize;}setMeasuredDimension(widthSize,widthSize);//设置view的宽高}private boolean isWhiteWin;private boolean isGameOver;private int MAX_CONUNT=5;//设置最大几子相连获胜

4.在onSizeChange()方法中去初始化棋盘的网格高度等一些数据(此方法是在onMeasure()调用之后执行的)

    //当测量工作完成时回调此方法@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {width=w;lineHeight=w*1.0f/lineNum;whitePiece=Bitmap.createScaledBitmap(whitePiece,(int)(intScale*lineHeight),(int)(intScale*lineHeight),false);//创建适应棋盘大小的的棋子Bitmap对象blackPiece=Bitmap.createScaledBitmap(blackPiece,(int)(intScale*lineHeight),(int)(intScale*lineHeight),false);}

Bitmap.createScaledBitmap这个api可以创建一个和原图一样的缩放的Bitmap对象

5.重写onTouchEvent()事件,把触摸的点的位置Point记录到集合中去

 private ArrayList whitePoints=new ArrayList<>();//点击网格时记录点击坐标的集合private ArrayList blackPoints=new ArrayList<>();private boolean isWhite=true;@Overridepublic boolean onTouchEvent(MotionEvent event) {if(isGameOver){if(isWhiteWin){Toast.makeText(getContext(),"白子胜利了!",Toast.LENGTH_SHORT).show();}else{Toast.makeText(getContext(),"黑子胜利了!",Toast.LENGTH_SHORT).show();}return false;}switch (event.getAction()){case MotionEvent.ACTION_DOWN://在按下的时候return turn;表明想获取到时间return true;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP://在Up时处理点击放置棋子的逻辑float x = event.getX();float y = event.getY();int pointX= (int) (x/lineHeight);int pointY= (int) (y/lineHeight);Point point=new Point(pointX,pointY);if(whitePoints.contains(point)||blackPoints.contains(point))return false;if(isWhite){whitePoints.add(point);}else{blackPoints.add(point);}isWhite=!isWhite;invalidate();return true;}return super.onTouchEvent(event);}

6.重写onDraw()方法

  private boolean isWhiteWin;private boolean isGameOver;private int MAX_CONUNT=5;//设置最大几子相连获胜@Overrideprotected void onDraw(Canvas canvas) {for(int i=0;i

因为画黑白棋子的逻辑都差不多,所以就把他们绘制的方法抽取出来

    private void drawPiece(List list,Bitmap bitmap,Canvas canvas){for (int i = 0; i < list.size(); i++) {Point point=list.get(i);canvas.drawBitmap(bitmap,(float)(lineHeight/2+lineHeight*point.x-intScale*lineHeight/2),(float)(lineHeight/2+lineHeight*point.y-intScale*lineHeight/2),piecePaint);}}

7.每次绘制的时候都要检查一下是否有五连的棋子

检测得方法也给抽取出来,分为横向五连的检测, 纵向五连的检测, 以及斜对角五连的检测

//检测棋子是否获胜,要检测每个棋子横向||纵向||斜方向上是否5连private boolean checkPieceIsWin(List list) {//check横向是否5连for (int i = 0; i < list.size(); i++) {boolean isHorizontalFive=checkHorizontal(list,list.get(i));if (isHorizontalFive)return true;continue;}//检查纵向是否5连for (int i = 0; i < list.size(); i++) {boolean isVerticalFive=checkVertical(list,list.get(i));if(isVerticalFive)return true;continue;}//检查斜向是否5连for (int i = 0; i < list.size(); i++) {boolean isSlantFive=checkSlant(list,list.get(i));if (isSlantFive)return true;continue;}return false;}

三种情况只要有一种符合就return true;然后就是每种检测的具体实现了

 //斜向检测private boolean checkSlant(List list, Point point) {int countLURD =1;int countLDRP =1;int x=point.x;int y=point.y;//检查左上5个for (int i = 1; i < MAX_CONUNT; i++) {if (list.contains(new Point(x-i,y-i))){countLURD++;}else{break;}}//检查右下5个for (int i = 1; i < MAX_CONUNT; i++) {if (list.contains(new Point(x+i,y+i))){countLURD++;}else{break;}}//检查右上5个for (int i = 1; i < MAX_CONUNT; i++) {if (list.contains(new Point(x+i,y-i))){countLDRP++;}else{break;}}//检查左下5个for (int i = 1; i < MAX_CONUNT; i++) {if(list.contains(new Point(x-i,y+i)))countLDRP++;break;}if(countLDRP>=5||countLURD>=5)return true;return false;}

 //纵向private boolean checkVertical(List list, Point point) {int count =1;int x=point.x;int y=point.y;//检查上边5个for (int i = 1; i < MAX_CONUNT; i++) {if (list.contains(new Point(x,y-i))){count++;}else{break;}}//检查下边5个for (int i = 1; i < MAX_CONUNT; i++) {if(list.contains(new Point(x,y+i)))count++;break;}if(count>=5)return true;return false;}

  //横向private boolean checkHorizontal(List list,Point point) {int count =1;int x=point.x;int y=point.y;//检查左边5个for (int i = 1; i < MAX_CONUNT; i++) {if (list.contains(new Point(x-i,y))){count++;}else{break;}}//检查右边5个for (int i = 1; i < MAX_CONUNT; i++) {if(list.contains(new Point(x+i,y)))count++;break;}if(count>=5)return true;return false;}

一旦返回true就在onDraw()方法中获取到,并且停止绘制,把isGameOVer变量=true;在下次onTouch的时候也不触发

8.最后就是考虑到数据的存储问题了,假设别人打电话过来,然后你接了电话,回来下好的棋子就没了,是不是很懊恼,其实View还有Activity都提供了

onSaveInstanceState()和onRestoreInstanceState(Parcelable state)一个是在View销毁的时候调用存储数据,一个是在View重置的时候把数据

取出来

   private final String INSTANCE="instance";private final String INSTANCE_GAME_OVER="instance_game_over";private final String INSTANCE_WHITE_LIST="instance_white_list";private final String INSTANCE_BLACK_LIST="instance_black_list";//Activity重建的时候把数据取出来,但是要想能够回到之前的状态,需要在布局中给他一个id@Overrideprotected Parcelable onSaveInstanceState() {Bundle bundle=new Bundle();bundle.putParcelable(INSTANCE,super.onSaveInstanceState());bundle.putParcelableArrayList(INSTANCE_BLACK_LIST,blackPoints);bundle.putParcelableArrayList(INSTANCE_WHITE_LIST,whitePoints);bundle.putBoolean(INSTANCE_GAME_OVER,isGameOver);return bundle;}//时在Activity走生命周期的时候记录下要保存的信息@Overrideprotected void onRestoreInstanceState(Parcelable state) {if(state instanceof Bundle){Bundle bundle=(Bundle)state;isGameOver=bundle.getBoolean(INSTANCE_GAME_OVER);super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));whitePoints=bundle.getParcelableArrayList(INSTANCE_WHITE_LIST);blackPoints=bundle.getParcelableArrayList(INSTANCE_BLACK_LIST);return;}super.onRestoreInstanceState(state);}
View重建的时候把数据取出来,但是要想能够回到之前的状态,但是需要在布局中给他一个id,否则View不能完成重建回复
最后完成了,你也可以把棋盘行数搞成一个自定义的属性,这样就可以在布局中给他设置行数了




本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部