首页 > 代码库 > 五子棋--自定义控件
五子棋--自定义控件
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); } }
五子棋--自定义控件
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。