Android之自定义五子棋View

最近没什么事情,学习了一下有关五子棋的自定义View,该View完成了简易五子棋自定义  主要使用了Android的自定义View,自定义了一个有关五子棋的View  ,其中包括棋盘网格线的绘制、棋子的绘制、规则的制定、输赢的提示 、还有最重要的当接到电话以及旋转屏幕等情况时  当前游戏状态的存储与恢复  以及"再来一局"。

放上View的完整代码,与各位共勉之。代码中添加了详细的注释,在此不做过多的解释,请自行查看注释。

 

 

完整Demo下载地址

 

public class WuZiQiPanel extends View {    private int mPanelWidth;//View的宽度    private float mLineHeight;//View中的行高    private int MAX_LINE = 10;//最大的行数    private int MAX_COUNT_IN_LINE = 5;//一条线上最大的棋子数为5    private Paint mPaint = new Paint();//创建Pain对象    //创建黑白棋子对象    private Bitmap mBlackPiece;    private Bitmap mWhitePiece;    //引入棋子的比例  是行高的四分之三    private float ratioPieceOffLineHeight = 3 * 1.0f / 4;    //判断是白棋先走    private boolean mIsWhite = true;    //存放黑白棋子放置的位置    private ArrayList mWhiteArray = new ArrayList<>();    private ArrayList mBlackArray = new ArrayList<>();    //判断游戏是否结束    private boolean mIsGameOver;    //判断是否白棋胜出    private boolean mIsWhiteWinner;    public WuZiQiPanel(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        //setBackgroundColor(0x44ff0000);        //初始化        init();    }    /**     * 初始化操作     */    private void init() {        //初始化Pint        mPaint.setColor(0x88000000);        mPaint.setAntiAlias(true);        mPaint.setDither(true);        mPaint.setStyle(Paint.Style.STROKE);        //初始化黑白棋子       /* mWhitePiece = BitmapFactory.decodeResource(getResources(), R.drawable.ic_wihte_img);        mBlackPiece = BitmapFactory.decodeResource(getResources(), R.drawable.ic_black_img);*/        mWhitePiece = BitmapFactory.decodeResource(getResources(), R.drawable.ic_white_img);        mBlackPiece = BitmapFactory.decodeResource(getResources(), R.drawable.ic_black_img);    }    /**     * 设置View的宽高     *     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int width = Math.min(widthSize, heightSize);        if (widthSize == MeasureSpec.UNSPECIFIED) {            width = heightSize;        } else if (heightSize == MeasureSpec.UNSPECIFIED) {            width = widthSize;        }        setMeasuredDimension(width, width);    }    /**     * 处理尺寸相关的操作     *     * @param w     * @param h     * @param oldw     * @param oldh     */    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mPanelWidth = w;        mLineHeight = mPanelWidth * 1.0f / MAX_LINE;        //初始化棋子的大小 行高的四分之三        int pieceWidth = (int) (mLineHeight * ratioPieceOffLineHeight);        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, pieceWidth, pieceWidth, false);        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, pieceWidth, pieceWidth, false);    }    /**     * 手势处理     *     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        if (mIsGameOver) return false;        int action = event.getAction();        if (action == MotionEvent.ACTION_UP) {            //获取手指触摸时的横纵坐标            int x = (int) event.getX();            int y = (int) event.getY();            Point point = getValidPoint(x, y);            //判断当前点击的位置是否有棋子  如果有  返回false            if (mWhiteArray.contains(point) || mBlackArray.contains(point)) {                return false;            }            if (mIsWhite) {                mWhiteArray.add(point);            } else {                mBlackArray.add(point);            }            //重置            invalidate();            mIsWhite = !mIsWhite;        }        return true;    }    /**     * 处理点击的坐标点     *     * @param x     * @param y     * @return     */    private Point getValidPoint(int x, int y) {        return new Point((int) (x / mLineHeight), (int) (y / mLineHeight));    }    /**     * 绘制     *     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //绘制棋盘        drawBoard(canvas);        //绘制棋子        drawPiece(canvas);        checkGameOver(canvas);    }    private void checkGameOver(Canvas canvas) {        boolean whiteWin = checkFiveInLine(mWhiteArray);        boolean blackWin = checkFiveInLine(mBlackArray);        if (whiteWin||blackWin){            mIsGameOver = true;            mIsWhiteWinner = whiteWin;            String text = mIsWhiteWinner?"白棋胜利":"黑棋胜利";            Toast.makeText(getContext(),text,Toast.LENGTH_LONG).show();        }    }    private boolean checkFiveInLine(List points) {        for (Point point : points) {            int x = point.x;            int y = point.y;            //检测横向是否成线            boolean win = checkHorizontal(x,y,points);            if (win) return true;            win = checkVertical(x,y,points);            if (win) return true;            win = checkLeftDiagonal(x,y,points);            if (win) return true;            win = checkRightDiagonal(x,y,points);            if (win) return true;        }        return false;    }    /**     * 判断x,y位置的棋子  是否横向有五个棋子相邻     * @param x     * @param y     * @param points     * @return     */    private boolean checkHorizontal(int x, int y, List points) {        int count = 1;        //左        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x-i,y))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        //有        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x+i,y))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        return false;    }    /**     * 判断x,y位置的棋子  是否纵向有五个棋子相邻     * @param x     * @param y     * @param points     * @return     */    private boolean checkVertical(int x, int y, List points) {        int count = 1;        //上        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x,y-i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        //下        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x,y+i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        return false;    }    /**     * 判断x,y位置的棋子  是否左斜方向有五个棋子相邻     * @param x     * @param y     * @param points     * @return     */    private boolean checkLeftDiagonal(int x, int y, List points) {        int count = 1;        //上        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x-i,y+i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        //下        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x+i,y-i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        return false;    }    /**     * 判断x,y位置的棋子  是否左斜方向有五个棋子相邻     * @param x     * @param y     * @param points     * @return     */    private boolean checkRightDiagonal(int x, int y, List points) {        int count = 1;        //上        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x-i,y-i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        //下        for (int i = 1; i < MAX_COUNT_IN_LINE; i++) {            if (points.contains(new Point(x+i,y+i))){                count++;            }else {                break;            }        }        if (count==MAX_COUNT_IN_LINE) return true;        return false;    }    /**     * 绘制棋子     *     * @param canvas     */    private void drawPiece(Canvas canvas) {        //绘制白棋        for (int i = 0; i < mWhiteArray.size(); i++) {            Point whitePoint = mWhiteArray.get(i);            canvas.drawBitmap(mWhitePiece,                    (whitePoint.x + (1 - ratioPieceOffLineHeight) / 2) * mLineHeight,                    (whitePoint.y + (1 - ratioPieceOffLineHeight) / 2) * mLineHeight, null);        }        //绘制黑棋        for (int i = 0; i < mBlackArray.size(); i++) {            Point whitePoint = mBlackArray.get(i);            canvas.drawBitmap(mBlackPiece,                    (whitePoint.x + (1 - ratioPieceOffLineHeight) / 2) * mLineHeight,                    (whitePoint.y + (1 - ratioPieceOffLineHeight) / 2) * mLineHeight, null);        }    }    /**     * 绘制棋盘     *     * @param canvas     */    private void drawBoard(Canvas canvas) {        int w = mPanelWidth;//获取棋盘的宽        float lineHeight = mLineHeight;//获取每一行的高        //棋盘上下左右分别空出半个行高(0.5个lineHeight)的外边距   所以棋盘的左上角网格的起始坐标是mLineHeight/2        for (int i = 0; i < MAX_LINE; i++) {            int startX = (int) (lineHeight / 2);//获取网格的起始坐标            int endX = (int) (w - lineHeight / 2);//获取网格的终止坐标            //获取纵坐标  注意上方有0.5个lineHeight的外边距            int y = (int) ((0.5 + i) * lineHeight);            //棋盘为正方形网格  纵向和横向的变化是一致的            //画横线            canvas.drawLine(startX, y, endX, y, mPaint);            //画纵线            canvas.drawLine(y, startX, y, endX, mPaint);        }    }    /**     * 再来一局     */    public void reStart(){        mWhiteArray.clear();        mBlackArray.clear();        mIsGameOver = false;        mIsWhiteWinner = false;        invalidate();    }    //View的存储与恢复    // 注意:如果下面代码完成后  View的状态依然有问题    // 检查XML中View的使用是否添加ID(必须有ID 下面代码才能正常)    private static final String  INSTANCE = "instance";    private static final String  INSTANCE_GAME_OVER = "instance_game_over";    private static final String  INSTANCE_WHITE_ARRAY = "instance_white_array";    private static final String  INSTANCE_BLACK_ARRAY = "instance_black_array";    @Nullable    @Override    protected Parcelable onSaveInstanceState() {        Bundle bundle = new Bundle();        bundle.putParcelable(INSTANCE,super.onSaveInstanceState());        bundle.putBoolean(INSTANCE_GAME_OVER,mIsGameOver);        bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY,mWhiteArray);        bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY,mBlackArray);        return bundle;    }    @Override    protected void onRestoreInstanceState(Parcelable state) {        if (state instanceof Bundle){            Bundle bundle = (Bundle) state;            mIsGameOver = bundle.getBoolean(INSTANCE_GAME_OVER);            mWhiteArray = bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY);            mBlackArray = bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY);            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));            return;        }        super.onRestoreInstanceState(state);    }}

 

更多相关文章

  1. Android中在GridView网格视图上实现item拖拽交换的方法
  2. 【Android】GridView添加网格线
  3. android GridView(网格视图)
  4. android基础控件(4)GridView实现网格视图
  5. 【Android 设计】:样式_ 触感 | 度量与网格
  6. Android UI控件详解-GridView(网格视图)
  7. Android 类似HTML 中Table的网格Table
  8. Android GridLayout网格布局、RadioGroup组合框

随机推荐

  1. java技术分享:jvm对java的原生锁做了哪些
  2. 【DB宝43】MySQL误操作闪回恢复利器之my2
  3. 大数据成神之路-Java高级特性增强(Concur
  4. 数据搬运组件:基于Sqoop管理数据导入和导
  5. CentOS下搭建MySql(RPM包)
  6. 大数据成神之路-Java高级特性增强(多线程
  7. 大数据成神之路-Java高级特性增强(Volati
  8. DolphinDB客户端软件教程
  9. Think PHP框架清除运行时缓存(php文件目录
  10. 无法访问此卷不包含可识别的文件系统 chk