android自定义View 五子棋小游戏

来源:互联网 发布:java开源网 编辑:程序博客网 时间:2024/05/21 06:52

做一个五子棋练练手,没什么特别的,再复习一下自定义View的知识,onMeasure,MeasureSpec , onDraw以及OnTouchEvent方法等,
效果图

这里写图片描述

代码如下:

package com.fivechess;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.view.MotionEvent;import android.view.View;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class GamePanel extends View {    //棋盘宽度    private int mPanelWidth ;    //每一个棋格的宽    private float mLineHeight ;    //棋盘最大的行数    private int MAX_LINE = 10 ;    //最多连线的棋子个数    private int MAX_COUNT_IN_LINE = 5 ;    private Paint mPaint = new Paint();    //定义黑白棋子的Bitmap    private Bitmap mWhitePiece ;    private Bitmap mBlackPiece ;    //棋子占一个棋格的比例,这里是3/4    private float ratioPieceOfLineHeight = 3 * 1.0f / 4 ;    private boolean isWhite = false ;    //存放已下过的棋子的数组    private ArrayList<Point> mWhiteArray = new ArrayList<>();    private ArrayList<Point> mBlackArray = new ArrayList<>();    //标识对局是否结束    private boolean isGameOver ;    //判断白棋是否获胜    private boolean isWhiteWinner ;    //构造方法    public GamePanel(Context context, AttributeSet attrs) {        super(context, attrs);        setBackgroundColor(0x80f8c866);        init();    }    //初始化画笔及Bitmap    private void init() {        mPaint.setColor(0x88000000);        mPaint.setAntiAlias(true);        mPaint.setDither(true);        mPaint.setStyle(Paint.Style.STROKE);        mWhitePiece = BitmapFactory.decodeResource(getResources() , R.drawable.white_chess) ;        mBlackPiece = BitmapFactory.decodeResource(getResources() , R.drawable.black_chess) ;    }    //测量过程    @Override    protected void onMeasure(int widthMeasureSpec, int 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( 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);        mPanelWidth = w ;        mLineHeight = mPanelWidth * 1.0f / MAX_LINE ;        int pieceWidth = (int) (mLineHeight * ratioPieceOfLineHeight);        mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece , pieceWidth , pieceWidth , false);        mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, pieceWidth , pieceWidth , false);    }    //绘制过程    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        drawBoard(canvas);        drawPieces(canvas) ;        checkGameOver();    }    //判断是否结束    private void checkGameOver() {        boolean whiteWin = checkFiveInLine( mWhiteArray );        boolean blackWin = checkFiveInLine( mBlackArray );        if( whiteWin || blackWin ){            isGameOver = true ;            isWhiteWinner = whiteWin ;            String text = isWhiteWinner ? "白棋胜利" : "黑棋胜利" ;            Toast.makeText(getContext() , text , Toast.LENGTH_SHORT).show();        }    }    //判断是否五子连珠    private boolean checkFiveInLine(List<Point> points) {        for( Point p : points ){            int x = p.x ;            int y = p.y ;            boolean win = checkHorizontal( x , y , points) ;            if( win ) return true ;            win = checkVertical( x , y , points) ;            if( win ) return true ;            win = checkLeftDown( x , y , points) ;            if( win ) return true ;            win = checkRightDown( x , y , points) ;            if( win ) return true ;        }        return false;    }    /**     * 判断x,y位置的棋子是否横向有相邻的5个一致     * @param x     * @param y     * @param points     * @return     */    private boolean checkHorizontal(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 ;    }    /**     * 判断x,y位置的棋子是否垂直方向有相邻的5个一致     * @param x     * @param y     * @param points     * @return     */    private boolean checkVertical(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 , 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 ;    }    private boolean checkLeftDown(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 + 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 ;    }    private boolean checkRightDown(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 - 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 ;    }    //绘制棋子的方法    private void drawPieces(Canvas canvas) {        for( int i = 0 , n = mWhiteArray.size() ; i < n ; i ++ ){            Point whitePoint = mWhiteArray.get(i);            canvas.drawBitmap(mWhitePiece, ( whitePoint.x + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight ,                    ( whitePoint.y + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight , null  );        }        for( int i = 0 , n = mBlackArray.size() ; i < n ; i ++ ){            Point blackPoint = mBlackArray.get(i);            canvas.drawBitmap(mBlackPiece, ( blackPoint.x + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight ,                    ( blackPoint.y + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight , null  );        }    }    //绘制棋盘的方法    private void drawBoard(Canvas canvas) {        int w = mPanelWidth ;        float lineHeight = mLineHeight ;        for( int i = 0 ; i < MAX_LINE ; i ++ ){            int startX = (int) (lineHeight/2);            int endX = (int) (w - lineHeight/2);            int y = (int) (( 0.5 + i ) * lineHeight);            //绘制棋盘的横线            canvas.drawLine(startX, y , endX , y , mPaint);            //绘制棋盘的竖线            canvas.drawLine(y , startX , y , endX , mPaint );        }    }    @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(  mWhiteArray.contains(p) || mBlackArray.contains(p) ){                return false ;            }            if( isWhite ){                mWhiteArray.add(p);            }else {                mBlackArray.add(p);            }            invalidate();            isWhite = !isWhite ;        }        return true;    }    //获取点击的有效地址    private Point getValidPoint(int x, int y) {        return new Point( (int )(x / mLineHeight) , (int ) (y / mLineHeight) );    }    //再来一局    public void restart(){        mWhiteArray.clear();        mBlackArray.clear();        isGameOver = false ;        isWhiteWinner = false ;        invalidate();    }/*    //定义常量    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 , isGameOver);        bundle.putParcelableArray(INSTANCE_WHITE_ARRAY ,  mWhiteArray);        bundle.putParcelableArray(INSTANCE_BLACK_ARRAY ,  mBlackArray);        return bundle ;    }    //恢复棋局状态    @Override    protected void onRestoreInstanceState(Parcelable state) {        if( state instanceof  Bundle ){            Bundle bundle = (Bundle) state;            isGameOver = 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);    }*/}

在布局文件中引入该View

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.fivechess.MainActivity"    android:background="@drawable/board_bg">    <com.fivechess.GamePanel        android:id="@+id/game_panel"        android:layout_width="match_parent"        android:layout_height="match_parent" />    <Button        android:id="@+id/button"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="再来一局"        android:layout_alignParentBottom="true"/></RelativeLayout>

MainActivity的代码

package com.fivechess;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity {    private Button button ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (Button) findViewById(R.id.button);        final GamePanel gamePanel = (GamePanel) findViewById(R.id.game_panel);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                gamePanel.restart();            }        });    }}