慕课上学习的五子棋

没有什么可讲的,我的注释写的很细了,核心的就是自定义的控件这个很重要的,整个类继承的VIew。

整个思想:

1、就是首先确定自定义控件的大小,我们用的是覆写onMeasure()方法确定大小:

    /***
     * 用于测量绘制  控制其子控件在父类中所占位置的大小  (继承View) 测量类
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        /***
         * 这个模式分为三种
         * AT_MOST(这个子控件可以制定大小,常量值是-2147483648)
         * EXACTLY (这个子控件根据父类进行调整,最大就是父类的大小,常量值是1073741824)
         * UNSPECIFIED (这个子控件是任意大小与父类无关,常量值是0)
         */

        Log.i(TAG, "widthSize—" + widthSize);
        Log.i(TAG, "widthMode—" + widthMode);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        Log.i(TAG, "heightSize—" + heightSize);
        Log.i(TAG, "heightMode—" + heightMode);
        int width = Math.min(widthSize, heightSize);
        Log.i(TAG, "—" + width);
        /*
         分辨率:
         widthSize—1080
         widthMode—1073741824   可以确定下来是子空间最大是父类布局的大小
         heightSize—1920
         heightMode—1073741824
         —1080*/
        Log.i(TAG, "" + MeasureSpec.UNSPECIFIED);
        Log.i(TAG, "" + MeasureSpec.AT_MOST);
        Log.i(TAG, "" + MeasureSpec.EXACTLY);

        if (widthMode == MeasureSpec.UNSPECIFIED) {
            width = heightSize;
            Log.i(TAG, "我不会被运行到1");
        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
            width = widthSize;
            Log.i(TAG, "我不会被运行到2");
        }
        setMeasuredDimension(width, width);//设置子控件的大小 该方法必须要在onMeasure调用
    }


2、初始化行高行宽,不同的设备屏幕尺寸不同为了合理使用的都是比例计算,覆写的onSizeChanged。

    /***
     * 当屏幕改变时进行调用运行
     *
     * @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);
        Log.i(TAG, "w" + w);//1080
        mPanelWidth = w;
        mLineHeight = mPanelWidth * 1.0f / MAX_LINE;
        //确定行高宽  将整个控件的宽平均分成10份,得出一份的宽度,因为是正方形所以也是高度 1080.0/10 = 108.0

        //改变棋子的尺寸
        int pieceWidth = (int) (mLineHeight * reatioPieceOfLineHeight);
        //确定棋子的高款为一个单位的高度宽度的3/4 108.0*3/4 = 81.0
        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, pieceWidth, pieceWidth, false);
        Log.i(TAG, "棋子的宽" + mWhitePiece.getWidth());//81.0
        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, pieceWidth, pieceWidth, false);
    }


3、绘制棋盘和棋子,当然覆写onDraw方法里了,在这个方法还要做一个判断胜利的监听。

    /***
     * 绘制棋盘
     *
     * @param canvas
     */
    private void drawBoard(Canvas canvas) {
        int w = mPanelWidth;//自定义view的宽度  1080
        float lineHeight = mLineHeight;//行高 108.0
        for (int i = 0; i < MAX_LINE; i++) {//绘制线
            int startX = (int) (lineHeight / 2);//54
            int endX = (int) (w - lineHeight / 2);//1026
            int y = (int) ((0.5 + i) * lineHeight);//y与行高的关系
            canvas.drawLine(startX, y, endX, y, mPaint);//绘制横线
            canvas.drawLine(y, startX, y, endX, mPaint);//绘制竖线
        }
    }

    /***
     * 绘制棋子
     *
     * @param canvas
     */
    private void drawPieces(Canvas canvas) {
        for (int i = 0, n = mWhiteArray.size(); i < n; i++) {
            Point whitePoint = mWhiteArray.get(i);
            Log.i(TAG, "whitePoint" + whitePoint);
            //drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
            canvas.drawBitmap(mWhitePiece, (whitePoint.x + (1 - reatioPieceOfLineHeight) / 2) * mLineHeight,//  3.0/4  -->  1.0/4  -->  1.0/8 -->
                    (whitePoint.y + (1 - reatioPieceOfLineHeight) / 2) * mLineHeight, null);
        }

        for (int i = 0, n = mBlackArray.size(); i < n; i++) {
            Point blackPoint = mBlackArray.get(i);
            //drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
            canvas.drawBitmap(mBlackPiece, (blackPoint.x + (1 - reatioPieceOfLineHeight) / 2) * mLineHeight,//  3.0/4  -->  1.0/4  -->  1.0/8 -->
                    (blackPoint.y + (1 - reatioPieceOfLineHeight) / 2) * mLineHeight, null);
        }
    }


    /***
     * 游戏胜利主监听
     */
    private void checkGameOver() {
        boolean whiteWin = checkFiveInLine(mWhiteArray);
        boolean blackWin = checkFiveInLine(mBlackArray);
        if (whiteWin || blackWin) {
            mIsGemeoVer = true;
            mIsWhiteWinner = whiteWin;
            String text = mIsWhiteWinner ? "白棋胜利" : "黑棋胜利";
            Toast.makeText(getContext(), text, Toast.LENGTH_SHORT).show();
        }
    }

Ps:自己画的两张草图


3、还有就是几个输赢逻辑判断(横线上连着五颗,竖着连着五颗,左斜着连着五颗,右斜这五颗)

    //横着
    private boolean checkWinHorizontal(int x, int y, List<Point> 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;
    }

4、覆写一个onTouchEvent对“下棋进行操作”,其实主要的还就是在数组列中添加坐标。

    public boolean onTouchEvent(MotionEvent event) {
        if (mIsGemeoVer) return false;//如果游戏结束,不能再次下子。
        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            int x = (int) event.getX();
            int y = (int) event.getY();
            //Point point = new Point(x, y);//确定的点
            Point point = getValidPoint(x, y);//不能重复下 ,不能下到一个点,不能仅仅根据坐标进行下棋所以有合理的点
            if (mWhiteArray.contains(point) || mBlackArray.contains(point)) {
                return false;
            }
            if (mIsWhite) {
                mWhiteArray.add(point);
            } else {
                mBlackArray.add(point);
            }
            invalidate();//刷新View
            mIsWhite = !mIsWhite;//改变值
            return true;
        }
        return true;
    }

5、作者还精心考虑到了关于资源文件配置出现变化,导致重构,比如你下着下着,然后突然横屏了,View就会重构,导致棋子清空。

/***
     * 防止View配置改变被杀死处理
     */
    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";

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(INSTANCE, super.onSaveInstanceState());

        bundle.putBoolean(INSTANCE_GAME_OVER, mIsGemeoVer);
        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;

            mIsGemeoVer = 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);
    }


6、再来一局进行的方法,我即使贴出来,但是不看源码,你是不知道这是怎么来的。

    public void agin() {
        mWhiteArray.clear();
        mBlackArray.clear();
        mIsGemeoVer = false;
        mIsWhiteWinner = false;
        invalidate();
    }

MainActivity中进行重来一局的监听。

       wuziqiPanel = (WuziqiPanel) findViewById(R.id.wuziqipanel);
        btnAginGame = (Button) findViewById(R.id.buttonAgin);
        btnAginGame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                wuziqiPanel.agin();
            }
        });

效果:

源码:http://download.csdn.net/detail/csdnhejingzhou/9513588

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值