Android - 五子棋

参考至慕课网:五子连珠 http://www.imooc.com/learn/641

1、源代码:

  wuziqiPanel

public class WuziqiPanel extends View {

    private int mPanelWidth;
    private float mLineHeight;
    private int MAX_LINE=10;
    private int MAX_PIECE_IN_LINE=5;

    private float ratioPieceOfLineHeight=3*1.0f/4;

    private Paint mPaint;
    private Bitmap mWhitePiece;
    private Bitmap mBlackPiece;

    private boolean mIsGameOver=false;
    private boolean mIsWhite=true; //轮到白棋
    private ArrayList<Point> mWhiteArray=new ArrayList<Point>();
    private ArrayList<Point> mBlackArray=new ArrayList<Point>();



    public WuziqiPanel(Context context) {
        super(context);
    }

    public WuziqiPanel(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    private void init(){
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        mWhitePiece= BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2);
        mBlackPiece= BitmapFactory.decodeResource(getResources(),R.drawable.stone_b1);
    }

    @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=w*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); //绘制棋盘
        drawPiece(canvas); //绘制棋子
    }

    private void drawPiece(Canvas canvas) {
        Point p;
        int x,y;
        for(int i=0,cnt=mWhiteArray.size();i<cnt;i++){
            p=mWhiteArray.get(i);
            x=(int)((p.x+0.5)*mLineHeight)-mWhitePiece.getWidth()/2;
            y=(int)((p.y+0.5)*mLineHeight)-mWhitePiece.getHeight()/2;
            canvas.drawBitmap(mWhitePiece,x,y,null);
        }
        for(int i=0,cnt=mBlackArray.size();i<cnt;i++){
            p=mBlackArray.get(i);
            x=(int)((p.x+0.5)*mLineHeight)-mBlackPiece.getWidth()/2;
            y=(int)((p.y+0.5)*mLineHeight)-mBlackPiece.getHeight()/2;
            canvas.drawBitmap(mBlackPiece, x, y, null);
        }
    }

    private void drawBoard(Canvas canvas){
        int w=mPanelWidth;
        float lineHeight=mLineHeight;

        for(int i=0;i<MAX_LINE;i++){
            int startX=(int)(0.5*lineHeight);
            int endX=(int)(w-0.5*lineHeight);
            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(mIsGameOver) return false;

        int action=event.getAction();
        if(action==MotionEvent.ACTION_UP){
            int x=(int)event.getX();
            int y =(int)event.getY();

            Point p=new Point((int)(x/mLineHeight),(int)(y/mLineHeight));

            if(mWhiteArray.contains(p)|| mBlackArray.contains(p)){
                return false;
            }

            if(mIsWhite){
                mWhiteArray.add(p);
            }else{
                mBlackArray.add(p);
            }

            invalidate();

            mIsGameOver= checkGameOver(mIsWhite, p); //判断胜负
            if(mIsGameOver){
                Toast.makeText(getContext(),mIsWhite?"白方胜利":"黑方胜利",Toast.LENGTH_SHORT).show();
            }

            mIsWhite=!mIsWhite;
        }
        return true;
    }

    private boolean checkGameOver(boolean isWhite, Point curPoint) {
        List<Point> pieceArray=null;
        if(isWhite){
            pieceArray=mWhiteArray;
        }else{
            pieceArray=mBlackArray;
        }

        return  checkFivePieceOnLine(pieceArray, curPoint, -1, 0) ||  // 横
                checkFivePieceOnLine(pieceArray, curPoint, 0, -1) ||  // 纵
                checkFivePieceOnLine(pieceArray, curPoint, -1, -1) || // 捺
                checkFivePieceOnLine(pieceArray, curPoint, 1, -1) ;   // 撇
    }

    private boolean checkFivePieceOnLine(List<Point> pieceArray, Point curPoint, int dx, int dy){
        int cnt=1;
        for(int i=1;cnt<MAX_PIECE_IN_LINE;i++){
            if(!pieceArray.contains(new Point(curPoint.x+dx*i,curPoint.y+dy*i))){
                break;
            }
            cnt++;
        }
        for(int i=1;cnt<MAX_PIECE_IN_LINE;i++){
            if(!pieceArray.contains(new Point(curPoint.x+(-dx)*i,curPoint.y+(-dy)*i))){
                break;
            }
            cnt++;
        }
        return cnt==MAX_PIECE_IN_LINE;
    }

    public void restartGame(){
        mIsWhite=true;
        mIsGameOver=false;
        mWhiteArray.clear();
        mBlackArray.clear();
        invalidate();
    }

    private static String INSTANCE="instance";
    private static String INSTANCE_WHITE_ARRAY="instance_white_array";
    private static String INSTANCE_BLACK_ARRAY="instance_black_array";
    private static String INSTANCE_IS_GAME_OVER="instance_is_game_over";
    private static String INSTANCE_IS_WHITE="instance_is_white";


    @Override
    protected Parcelable onSaveInstanceState() {

        Bundle bundle=new Bundle();
        bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
        bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY,mWhiteArray);
        bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY,mBlackArray);
        bundle.putBoolean(INSTANCE_IS_GAME_OVER, mIsGameOver);
        bundle.putBoolean(INSTANCE_IS_WHITE,mIsWhite);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {

        if(state instanceof Bundle){
            Bundle bundle=(Bundle)state;
            mWhiteArray=bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY);
            mBlackArray=bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY);
            mIsGameOver=bundle.getBoolean(INSTANCE_IS_GAME_OVER);
            mIsWhite=bundle.getBoolean(INSTANCE_IS_WHITE);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
            return ;
        }

        super.onRestoreInstanceState(state);
    }
}

  MainActivity.java

public class MainActivity extends AppCompatActivity {

    private WuziqiPanel mWuziqiPanel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWuziqiPanel=(WuziqiPanel)findViewById(R.id.wuziqiPanel);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main,menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.action_restartGame:
                mWuziqiPanel.restartGame();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}

  activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="@mipmap/bg"
    android:orientation="vertical"
    android:gravity="center"
    tools:context="com.yizhui.imooc_wuziqi.MainActivity">

 <com.yizhui.imooc_wuziqi.WuziqiPanel
     android:id="@+id/wuziqiPanel"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_centerInParent="true"/>

</LinearLayout>

 2、

自定义View 重要的几个重载方法: onMeasure、onTouchEvent、onDraw

onMeasure 中处理特殊布局嵌套时尺寸测量(如,嵌套在ScrollView中):MeasureSpec.UNSPECIFIED

onSizeChanged:处理尺寸大小变化时逻辑

onTouchEvent:控件OnTouchEvent方法中,返回True,才会继续触发后面的action(ACTION_DOWN,ACTION_MOVE,ACTION_UP)

自定义View状态保存:

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle=new Bundle();
        bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
        bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY,mWhiteArray);
        bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY,mBlackArray);
        bundle.putBoolean(INSTANCE_IS_GAME_OVER, mIsGameOver);
        bundle.putBoolean(INSTANCE_IS_WHITE,mIsWhite);
        return bundle;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if(state instanceof Bundle){
            Bundle bundle=(Bundle)state;
            mWhiteArray=bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY);
            mBlackArray=bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY);
            mIsGameOver=bundle.getBoolean(INSTANCE_IS_GAME_OVER);
            mIsWhite=bundle.getBoolean(INSTANCE_IS_WHITE);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
            return ;
        }
        super.onRestoreInstanceState(state);
    }

  

 


 

posted @ 2016-04-21 18:52  chenyizh  阅读(187)  评论(0)    收藏  举报