详细注释-Android五子棋

棋盘的绘制

棋盘是10*10的风格,使用自定义View来对棋盘的线进行绘制


话不多说,直接上代码
WuZiQiPanel类继承View,重写构造函数,onMesure(),onSizeChanged(),onDraw()。

public class WuZiQiPanel extends View {

    private int mPanelwidth;//棋盘的宽高
    private float mLineheight; //每一行的高度
    private int MAX_LINE =10;//十行的棋
    private int MAX_COUNT_IN_LINE =5;//棋子五个数
    Paint paint  = new Paint();

    private Bitmap mWhitePiece;
    private Bitmap mBlackPiece;
    private boolean mIsWhitePice = true;//判断是否是白旗
    private float PieceOfLineHeight=3*1.f/4;//每个棋子站3/4的LineHeight

    private boolean mWhiteWinner;
    private boolean IsGameOver;


    private List<Point> mWhitePieceList = new ArrayList<>();
    private List<Point> mBlackPieceList = new ArrayList<>();

    public WuZiQiPanel(Context context, AttributeSet attrs) {
        super(context, attrs);
        setBackgroundColor(0x44ff0000);
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //通过widthMeasureSpec拿到宽度尺寸大小
        //widthMeasureSpec,heightMeasureSpec 模式和尺寸组合在一起的数值
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);//得到宽尺寸
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);//等到宽模式

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        /**
         * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, MeasureSpec.AT_MOST。

         MeasureSpec.EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。

         MeasureSpec.AT_MOST是最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。

         MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式。
         */

        int width = Math.min(widthSize,heightSize);//正方形

        if(widthMode == MeasureSpec.UNSPECIFIED){
            width = heightSize;
        }else if(heightMode == MeasureSpec.UNSPECIFIED){
            width = widthSize;
        }
        setMeasuredDimension(width,width);//设置实际大小
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.d("onSizeChanged w",w+"");
        mPanelwidth = w;
        mLineheight = mPanelwidth*1.0f/MAX_LINE;//转化成浮点数后分为10,求出每个方格的高度

        int pieceSize =(int) (mLineheight*PieceOfLineHeight);
        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece,pieceSize,pieceSize,false);//设置宽高
        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece,pieceSize,pieceSize,false);//设置宽高
    }

    /**
     * 绘制视图
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBoard(canvas);
        drawPiece(canvas);
        cheakGameOver();
    }

    /**
     * 判断游戏结束,核心算法
     */
    private void cheakGameOver() {

        boolean whiteWin = cheakWinner(mWhitePieceList);//检查白子的五子
        boolean blackWin = cheakWinner(mBlackPieceList);
        if(whiteWin||blackWin){
            IsGameOver = true;
            mWhiteWinner = whiteWin;
            String text = mWhiteWinner?"白棋":"黑棋";
            Toast.makeText(getContext(),text,Toast.LENGTH_SHORT).show();
        }

    }

    /**
     * 判断白子是否有五子
     * @param point
     * @return
     */
    private boolean cheakWinner(List<Point> point) {

        for(Point p:point){
            int x =p .x;
            int y = p.y;
           boolean win =  checkHorizontal(x,y,point);
            if(win) return true;
            win =checkLeft(x,y,point);
            if(win) return true;
            win =checkRight(x,y,point);
            if(win) return true;
            win =checkVertical(x,y,point);
            if(win) return true;
        }
        return false;
    }

    /**
     * 判断横向棋子是否五子连珠
     * @param x
     * @param y
     * @param point
     * @return
     */
    private boolean checkHorizontal(int x, int y, List<Point> point) {
        int count =1;
        //判断左边的棋子
        for(int i = 1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x-i,y))){
                count++;
            }else{
                break;
            }
        }
        //判断右边
        for(int i=1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x+i,y))){
                count++;
            }else{
                break;
            }
        }
        if(count==MAX_COUNT_IN_LINE)
            return true;
        return false;
    }

    /**
     * 纵向
     * @param x
     * @param y
     * @param point
     * @return
     */
    private boolean checkVertical(int x, int y, List<Point> point) {
        int count =1;

        for(int i = 1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x,y+i))){
                count++;
            }else{
                break;
            }
        }
        for(int i=1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x,y-i))){
                count++;
            }else{
                break;
            }
        }
        if(count==MAX_COUNT_IN_LINE)
            return true;
        return false;
    }

    /**
     * 左斜
     * @param x
     * @param y
     * @param point
     * @return
     */
    private boolean checkLeft(int x, int y, List<Point> point) {
        int count =1;
        //判断上的棋子
        for(int i = 1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x-i,y+i))){
                count++;
            }else{
                break;
            }
        }
        //判断右边
        for(int i=1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x+i,y-i))){
                count++;
            }else{
                break;
            }
        }
        if(count==MAX_COUNT_IN_LINE)
            return true;
        return false;
    }

    /**
     * 右斜
     * @param x
     * @param y
     * @param point
     * @return
     */
    private boolean checkRight(int x, int y, List<Point> point) {
        int count =1;
        //判断上的棋子
        for(int i = 1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x-i,y-i))){
                count++;
            }else{
                break;
            }
        }
        //判断右边
        for(int i=1;i<MAX_COUNT_IN_LINE;i++){
            if(point.contains(new Point(x+i,y+i))){
                count++;
            }else{
                break;
            }
        }
        if(count==MAX_COUNT_IN_LINE)
            return true;
        return false;
    }
    /**
     * 绘制棋子
     * (1-PieceOfLineHeight)/2  是棋子两边距离LineHeight的长度
     * @param canvas
     */
    private void drawPiece(Canvas canvas) {
        for(int i=0;i<mWhitePieceList.size();i++){
            Point white = mWhitePieceList.get(i);
            canvas.drawBitmap(mWhitePiece,(white.x+(1-PieceOfLineHeight)/2)*mLineheight,(white.y+(1-PieceOfLineHeight)/2)*mLineheight,null);
        }
        for(int i=0;i<mBlackPieceList.size();i++){
            Point black = mBlackPieceList.get(i);
            canvas.drawBitmap(mBlackPiece,(black.x+(1-PieceOfLineHeight)/2)*mLineheight,(black.y+(1-PieceOfLineHeight)/2)*mLineheight,null);
        }
    }

    /**
     * 绘制棋盘
     * @param canvas
     */
    private void drawBoard(Canvas canvas) {
        int w = mPanelwidth;//拿到棋盘宽度
        float lineheight = mLineheight;

        for(int i=0;i<MAX_LINE;i++){
            int starx = (int)(lineheight/2);//x轴起点
            int endx = (int)(w-lineheight/2);//x轴终点

            int y = (int)((0.5+i)*lineheight);//y
          // Log.d("y",y+"");
            canvas.drawLine(starx,y,endx,y,paint);
            canvas.drawLine(y,starx,y,endx,paint);
        }
    }

    /**
     * 复写onTouchEvent事件对用户点击事件进行处理
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if(IsGameOver)    //游戏结束就不再落子
            return false;
        int action = event.getAction();
        if(action == MotionEvent.ACTION_UP){
            int x = (int) event.getX();
            int y = (int) event.getY();

            Point p = getValidPoint(x,y);
            if(mBlackPieceList.contains(p)||mWhitePieceList.contains(p)){
                return false;
            }
            //加入List中
            if(mIsWhitePice){
                mWhitePieceList.add(p);
            }else{
                mBlackPieceList.add(p);
            }
            mIsWhitePice = !mIsWhitePice;
            invalidate();//重绘


        }
        return true;//表示事件被消费
    }

    /**
     * 处理点击事件的取值,防止图片偏移
     * @param x
     * @param y
     * @return
     */
    private Point getValidPoint(int x, int y) {

        return new Point((int)(x/mLineheight), (int) (y/mLineheight));
    }

    /**
     * 初始化方法
     *
     */
    private void init(){
        paint.setColor(0x88000000);//半透明灰色
        paint.setAntiAlias(true);//防锯齿
        paint.setDither(true);//防抖动
        paint.setStyle(Paint.Style.STROKE);//画线

        mWhitePiece = BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2);
        mBlackPiece = BitmapFactory.decodeResource(getResources(),R.drawable.stone_b1);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        Log.d("onFinishInflate","onFinishInflate");
    }
}

这里写图片描述

思路流程

Created with Raphaël 2.1.0 下棋(绘制棋盘填充图片) 响应用户onTouchEvent事件,每次响应都更新View onDraw()中要不断画View,判断是否有五子连珠 游戏结束

makedown流程图

st=>start: 下棋(绘制棋盘填充图片)
e=>end: 游戏结束
op1=>operation: 响应用户onTouchEvent事件,每次响应都更新View
op2=>operation: onDraw()中要不断画View,判断是否有五子连珠
st->op1->op2->e

感觉还是挺方便的,分支的话还没有写,不过看看啦,代码就这些,会传到本人的Github上

游戏

这里写图片描述

[Github下载地址](https://github.com/w77996/WuZiQi

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值