• 五子棋--自定义控件


    package com.example.administrator.viewapp;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.os.Bundle;
    import android.os.Parcelable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    
    /**
     * Created by Zyh on 2016/11/18.
     */
    public class WuZiPanel extends View {
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //系统传递的参数widthMeasureSpec和heightMeasureSpec,我们可以根据这两个参数获取当前控件的宽高
            //首先获取当前的大小
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            //我们画正方形需要去宽和高中的最小值
            int width = Math.min(widthSize, heightSize);
            //然后将测量的结果设置给系统,这个方法是最终设置自定义view大小的方法
            setMeasuredDimension(width, width);
    //        Log.d("系统给我们的宽度-------------->", "" + width);
    //        Log.d("系统给我们的宽度(转换后)---->", widthSize+"----" + heightSize);
            //初始化棋盘宽度和线的间距,需要在setMeasureDimsion之后进行
        }
    
        //在onMeasure中调用setMeasuredDimension方法之后,接下来系统会执行onSizeChanged方法
        //所以初始化棋盘宽度和线的间距要在onSizeChanged中进行
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            Log.d("new-----------",w+"----"+h);
            Log.d("old-----------",oldw+"---"+oldh);
            mPanelWidth = w;
            mLineHeight = w * 1.0f / MAX_LIME;//首先将宽度转换成float类型
            //规定旗子的宽高
            int width = (int) (mLineHeight * 3 / 4);
            //按比例重新设置宽高
            mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, width, width, false);
            mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, width, width, false);
        }
        //初始化画笔,
        private Paint mPaint = new Paint();
        //横线竖线的数量,
        private static final int MAX_LIME = 12;
        //棋盘的宽度,和高度
        private int mPanelWidth;
        //线和线之间的间距
        private float mLineHeight;
        //记录白棋和黑棋的落子位置
        private ArrayList<Point> mWhiteArry = new ArrayList<>();
        private ArrayList<Point> mBlackArray = new ArrayList<>();
        private boolean mIsWhite = true;//判断目前谁走
    
        //系统会默认调用两个参数的构造方法
        public WuZiPanel(Context context, AttributeSet attrs) {
            super(context, attrs);
    //        0X--代表16进制的数值的写法前缀
            setBackgroundColor(0x66ff0000);
            mPaint.setStrokeWidth(2);//设置画笔的宽度
            mPaint.setTextSize(18);
            inte();
        }
        private void inte() {
            mPaint.setColor(0xaa000000);
            mPaint.setStyle(Paint.Style.STROKE); //设置划一条线
            mWhitePiece = BitmapFactory.decodeResource(getResources(), R.mipmap.baizi);
            mBlackPiece = BitmapFactory.decodeResource(getResources(), R.mipmap.heizi);
    
        }
    
        /**
         * onTouchEvent内有四个返回值:true,false,和super.onTouchEvent(event)
         * true:表示拦截此次事件,不再交给其他方法使用
         * false:表示对此次事件不感兴趣,让系统分发给其他的方法
         *
         * @param event
         * @return
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            //游戏已结束那么点击事件就不关心了
            if (misGameOver){
                return false;
            }
            //MotionEvent.ACTION_DOWN--指鼠标点下的事件
            //MotionEvent.ACTION_UP---指鼠标抬起的事件
            if (event.getAction() == MotionEvent.ACTION_UP) {
    //            Toast.makeText(getContext(), "鼠标抬起事件", Toast.LENGTH_SHORT).show();
                int x = (int) event.getX();
                int y = (int) event.getY();
                Point p = new Point((int) (x / mLineHeight), (int) (y / mLineHeight));
                //表示不能重复落子,那么此次的点击事件我们交给系统,我们不做任何的处理
                if (mWhiteArry.contains(p) || mBlackArray.contains(p)) {
                    return false;
                }
                //如果正确落子,记录当前的落子的位置,并将它加入黑白集合当中
                mCurPoint=p;
    //            Toast.makeText(getContext(), (int) (y / mLineHeight) + "当前交叉点的坐标" + (int) (x / mLineHeight), Toast.LENGTH_SHORT).show();
               //判断该谁走
                if (mIsWhite) {
                    mWhiteArry.add(new Point((int) (x / mLineHeight), (int) (y / mLineHeight)));
                    mIsWhite = false;
                } else {
                    mBlackArray.add(new Point((int) (x / mLineHeight), (int) (y / mLineHeight)));
                    mIsWhite = true;
                }
    //            Toast.makeText(getContext(), x + "---" + y, Toast.LENGTH_SHORT).show();
                //记录下点击的位置,请求重新绘制界面,重新调用onDraw方法
                invalidate();//作用重新调用onDraw
                postInvalidate();//请求在非UI线程中重绘
    
                return true;//这里代表我们已经处理过点击事件不需要去返回给系统
            }
            //我们必须首先将点击下的动作拦截下来才能接下来拦截抬起的动作
            else if (event.getAction() == MotionEvent.ACTION_DOWN) {
    //            Toast.makeText(getContext(), "鼠标抬起事件", Toast.LENGTH_SHORT).show();
                return true;
            }
            return super.onTouchEvent(event);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /**canvas---画布,系统提供
             canvas.drawLine(0,0,300,300,mPaint);//画一条线:参数起始的坐标和终止的坐标以及画笔
             canvas.drawCircle(150,150,40,mPaint);//画圆,起始坐标指定的是圆心的坐标
             canvas.drawText("我的世界",150,150,mPaint);//写字,参数说明:字体,起始坐标,画笔
             canvas.drawRect(10,10,200,200,mPaint);//画矩形
             画Bitmap,
             canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher),0,0,mPaint);
             */
            drawBoard(canvas);
            drawPiece(canvas);
            //每一次落子之后都要进行胜负判断
            checkGameIsOver();
        }
        private boolean misGameOver=false;
        private boolean misWhiteWinner=false;
        private void checkGameIsOver() {
            boolean isBlackWin=false;
            boolean isWhiteWin=false;
            if (mIsWhite){
                isBlackWin=checkFiveInLine(mBlackArray);
            }else {
                isWhiteWin=checkFiveInLine(mWhiteArry);
            }
            if (isBlackWin||isWhiteWin){
                //只要有一个胜利,那么游戏就结束
                misGameOver=true;
                misWhiteWinner=isWhiteWin;
                //写一个监听的接口,将胜负发送到对应的activity中处理
                //问号在这里表示判断的
                String str=misWhiteWinner?"白棋胜利":"黑棋胜利";
                Toast.makeText(getContext(),str, Toast.LENGTH_SHORT).show();
            }
        }
        private Point mCurPoint;
    
        private boolean checkFiveInLine(ArrayList<Point> mArry) {
            //如果落下的是白子,mIsWhite是false,如果落下的是黑子,那么mIsWhite是true
    //        if ((!mIsWhite&&isWhite)||(mIsWhite&&!isWhite)){
    //            //mCurPoint白棋+白棋mArray或者mCurPoint黑棋+黑棋mArray
    //            //符合这两种情况接下来往下判断,否则跳出
    //        }else {
    //            return false;
    //        }
            //如果当前位置旗子的位置不为空,判断他的四个方向是否满足胜利条件
            if (mCurPoint!=null){
    //            Toast.makeText(getContext(),x+""+y, Toast.LENGTH_SHORT).show();
               if (checkHorIsFive(mArry,mCurPoint))
                   return true;
                if (checkVerIsFive(mArry,mCurPoint)){
                    return true;
                }
                if (checkRightAngileIsFive(mArry,mCurPoint)){
                    return true;
                }
                if (checkLelfeAngileIsFive(mArry,mCurPoint)){
                    return true;
                }
            }
    
            return false;
        }
    
        private boolean checkHorIsFive(ArrayList<Point> mArry,Point mPoint) {
            //首先判断横向是否凑齐五个子 第二次遍历向右判断
            int x=mCurPoint.x;
            int y=mCurPoint.y;
            int count=1;
            boolean isFirstBreak=true;
            boolean isSecondBreak=true;
            for (int i=1;i<5;i++){
                if (isFirstBreak){
                    if (mArry.contains(new Point(x-i,y))){
                        count++;
                    }else {
                        //向右判断
                        isFirstBreak=false;
                    }
                }
                //如果是true的话,就代表当前位置旗子右边有相同的子,count加1
                if (isSecondBreak){
                    if (mArry.contains(new Point(x+i,y))){
                        count++;
                    }else {
                        //向右判断
                        isSecondBreak=false;
                    }
                }
                //如果已经达到5颗子,跳出循环
            }
            if(count==5){
                return true;
            }else {
                return false;
            }
        }
        private boolean checkVerIsFive(ArrayList<Point> mArry,Point mPoint) {
            //首先判断横向是否凑齐五个子 第二次遍历向右判断
            int x=mCurPoint.x;
            int y=mCurPoint.y;
            int count=1;
            boolean isFirstBreak=true;
            boolean isSecondBreak=true;
            for (int i=1;i<5;i++){
                if (isFirstBreak){
                    if (mArry.contains(new Point(x,y-i))){
                        count++;
                    }else {
                        //向右判断
                        isFirstBreak=false;
                    }
                }
                //如果是true的话,就代表当前位置旗子右边有相同的子,count加1
                if (isSecondBreak){
                    if (mArry.contains(new Point(x,y+i))){
                        count++;
                    }else {
                        //向右判断
                        isSecondBreak=false;
                    }
                }
                //如果已经达到5颗子,跳出循环
            }
            if(count==5){
                return true;
            }else {
                return false;
            }
        }
        private boolean checkRightAngileIsFive(ArrayList<Point> mArry,Point mPoint) {
            //首先判断横向是否凑齐五个子 第二次遍历向右判断
            int x=mCurPoint.x;
            int y=mCurPoint.y;
            int count=1;
            boolean isFirstBreak=true;
            boolean isSecondBreak=true;
            for (int i=1;i<5;i++){
                if (isFirstBreak){
                    if (mArry.contains(new Point(x-i,y-i))){
                        count++;
                    }else {
                        //向右判断
                        isFirstBreak=false;
                    }
                }
                //如果是true的话,就代表当前位置旗子右边有相同的子,count加1
                if (isSecondBreak){
                    if (mArry.contains(new Point(x+i,y+i))){
                        count++;
                    }else {
                        //向右判断
                        isSecondBreak=false;
                    }
                }
                //如果已经达到5颗子,跳出循环
            }
            if(count==5){
                return true;
            }else {
                return false;
            }
        }
        private boolean checkLelfeAngileIsFive(ArrayList<Point> mArry,Point mPoint) {
            //首先判断横向是否凑齐五个子 第二次遍历向右判断
            int x=mCurPoint.x;
            int y=mCurPoint.y;
            int count=1;
            boolean isFirstBreak=true;
            boolean isSecondBreak=true;
            for (int i=1;i<5;i++){
                if (isFirstBreak){
                    if (mArry.contains(new Point(x-i,y+i))){
                        count++;
                    }else {
                        //向右判断
                        isFirstBreak=false;
                    }
                }
                //如果是true的话,就代表当前位置旗子右边有相同的子,count加1
                if (isSecondBreak){
                    if (mArry.contains(new Point(x+i,y-i))){
                        count++;
                    }else {
                        //向右判断
                        isSecondBreak=false;
                    }
                }
                //如果已经达到5颗子,跳出循环
            }
            if(count==5){
                return true;
            }else {
                return false;
            }
        }
    
        private void drawPiece(Canvas canvas) {
            //画旗子的方法
            for (int i = 0; i < mWhiteArry.size(); i++) {
                Point point = mWhiteArry.get(i);
                float x = (float) ((point.x + 1.0 / 8) * mLineHeight);
                float y = (float) ((point.y + 1.0 / 8) * mLineHeight);
                canvas.drawBitmap(mWhitePiece, x, y, null);
            }
            for (int i = 0; i < mBlackArray.size(); i++) {
                Point point = mBlackArray.get(i);
                float x = (float) ((point.x + 1.0 / 8) * mLineHeight);
                float y = (float) ((point.y + 1.0 / 8) * mLineHeight);
                canvas.drawBitmap(mBlackPiece, x, y, null);
            }
        }
    
        private Bitmap mWhitePiece;
        private Bitmap mBlackPiece;
    
        private void drawBoard(Canvas canvas) {
            int w = mPanelWidth;
            float lineHeight = mLineHeight;
            for (int i = 0; i < MAX_LIME; i++) {
                int startX = (int) (lineHeight / 2);
                int endX = w - startX;
                int Y = (int) ((0.5 + i) * lineHeight);
                canvas.drawLine(startX, Y, endX, Y, mPaint);
            }
            for (int i = 0; i < MAX_LIME; i++) {
                int starY = (int) (lineHeight / 2);
                int X = (int) ((int) (lineHeight / 2) + i * lineHeight);
                int endY = (int) (w - lineHeight / 2);
                canvas.drawLine(X, starY, X, endY, mPaint);
            }
        }
    
        /**
         * 状态的保存和恢复,
         * @return
         */
    private  static final String INSTANCE="INSTANCE";
        private  static final String INSTANCE_mWhiteArry="mWhiteArry";
        private  static final String INSTANCE_mBlackArray="mBlackArray";
        private  static final String INSTANCE_misGameOver="misGameOver";
        private  static final String INSTANCE_mIsWhite="mIsWhite";
        @Override
        protected Parcelable onSaveInstanceState() {
            Bundle bundle=new Bundle();
            bundle.putParcelableArrayList(INSTANCE_mWhiteArry,mWhiteArry);
            bundle.putParcelableArrayList(INSTANCE_mBlackArray,mBlackArray);
            bundle.putBoolean(INSTANCE_misGameOver,misGameOver);
            bundle.putBoolean(INSTANCE_mIsWhite,mIsWhite);
            bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
            return bundle;
        }
    
        @Override
        protected void onRestoreInstanceState(Parcelable state) {
            //如果是bundle类型就表明我们传递的有值,屏幕发生旋转或者activity强制被杀死,保存过信息
            if (state instanceof Bundle){
                Bundle bundle= (Bundle) state;
                mIsWhite=bundle.getBoolean(INSTANCE_mIsWhite,false);
                misGameOver=bundle.getBoolean(INSTANCE_misGameOver,false);
                mBlackArray=bundle.getParcelableArrayList(INSTANCE_mBlackArray);
                mWhiteArry=bundle.getParcelableArrayList(INSTANCE_mWhiteArry);
                super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
                return;
            }
            super.onRestoreInstanceState(state);
        }
    
    
    }
  • 相关阅读:
    并发编程的艺术
    Redis字符串实现,SDS与C的区别,空间预分配
    Jvm
    Redis数据结构的实现
    发一篇感谢身边的所有从事it工作的朋友
    BeanFactory 默认的注入实现类DefaultListableBeanFactory
    jsSwitch语句优化
    彻底搞懂 Nginx 的五大应用场景
    Spring Boot 整合 Quartz 轻松实现任务调度!
    js计算两个给定日期之间的天数
  • 原文地址:https://www.cnblogs.com/zhaiyaohua/p/6088192.html
Copyright © 2020-2023  润新知