android自定義View實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
做一個(gè)五子棋練練手,沒什么特別的,再復(fù)習(xí)一下自定義View的知識(shí),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 ; ? ? //每一個(gè)棋格的寬 ? ? private float mLineHeight ; ? ? //棋盤最大的行數(shù) ? ? private int MAX_LINE = 10 ; ? ? //最多連線的棋子個(gè)數(shù) ? ? private int MAX_COUNT_IN_LINE = 5 ; ? ? private Paint mPaint = new Paint(); ? ? //定義黑白棋子的Bitmap ? ? private Bitmap mWhitePiece ; ? ? private Bitmap mBlackPiece ; ? ? //棋子占一個(gè)棋格的比例,這里是3/4 ? ? private float ratioPieceOfLineHeight = 3 * 1.0f / 4 ; ? ? private boolean isWhite = false ; ? ? //存放已下過的棋子的數(shù)組 ? ? private ArrayList<Point> mWhiteArray = new ArrayList<>(); ? ? private ArrayList<Point> mBlackArray = new ArrayList<>(); ? ? //標(biāo)識(shí)對(duì)局是否結(jié)束 ? ? private boolean isGameOver ; ? ? //判斷白棋是否獲勝 ? ? private boolean isWhiteWinner ; ? ? //構(gòu)造方法 ? ? 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) ; ? ? } ? ? //測(cè)量過程 ? ? @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(); ? ? } ? ? //判斷是否結(jié)束 ? ? 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個(gè)一致 ? ? ?* @param x ? ? ?* @param y ? ? ?* @param points ? ? ?* @return ? ? ?*/ ? ? private boolean checkHorizontal(int x, int y, List<Point> points) { ? ? ? ? //五個(gè)子的計(jì)數(shù)器 ? ? ? ? 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個(gè)一致 ? ? ?* @param x ? ? ?* @param y ? ? ?* @param points ? ? ?* @return ? ? ?*/ ? ? private boolean checkVertical(int x, int y, List<Point> points) { ? ? ? ? //五個(gè)子的計(jì)數(shù)器 ? ? ? ? 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) { ? ? ? ? //五個(gè)子的計(jì)數(shù)器 ? ? ? ? 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) { ? ? ? ? //五個(gè)子的計(jì)數(shù)器 ? ? ? ? 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; ? ? } ? ? //獲取點(diǎn)擊的有效地址 ? ? 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"; ? ? //保存當(dāng)前游戲狀態(tài) ? ? @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 ; ? ? } ? ? //恢復(fù)棋局狀態(tài) ? ? @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(); ? ? ? ? ? ? } ? ? ? ? }); ? ? } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Win10下android studio開發(fā)環(huán)境配置圖文教程
這篇文章主要為大家詳細(xì)介紹了Win10下android studio開發(fā)環(huán)境配置圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07android中ListView多次刷新重復(fù)執(zhí)行g(shù)etView的解決方法
以前倒是沒有注意listview的getView會(huì)重復(fù)執(zhí)行多次,在測(cè)試的時(shí)候去斷點(diǎn)跟蹤,發(fā)現(xiàn)同一條數(shù)據(jù)不斷的重復(fù)執(zhí)行,下面與大家分享下正確的解決方法,希望對(duì)你有所幫助2013-06-06Android開發(fā)中PopupWindow用法實(shí)例分析
這篇文章主要介紹了Android開發(fā)中PopupWindow用法,結(jié)合實(shí)例形式分析了PopupWindow彈出窗口效果的使用技巧,需要的朋友可以參考下2016-02-02Android實(shí)戰(zhàn)教程第三篇之簡(jiǎn)單實(shí)現(xiàn)撥打電話功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)戰(zhàn)教程第三篇之簡(jiǎn)單實(shí)現(xiàn)撥打電話功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android開發(fā)實(shí)現(xiàn)加載網(wǎng)絡(luò)圖片并下載至本地SdCard的方法
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)加載網(wǎng)絡(luò)圖片并下載至本地SdCard的方法,涉及Android圖片文件的讀取、保存及權(quán)限相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Android圖表庫HelloCharts的實(shí)例詳解
這篇文章主要介紹了Android中的圖標(biāo)庫HelloCharts的一些簡(jiǎn)單使用實(shí)例,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定的參考價(jià)值,需要的可以參考一下2022-01-01Android中PopuWindow實(shí)現(xiàn)下拉列表實(shí)例
本篇文章主要介紹了Android中PopuWindow實(shí)現(xiàn)下拉列表實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07Android自定義Button并設(shè)置不同背景圖片的方法
這篇文章主要介紹了Android自定義Button并設(shè)置不同背景圖片的方法,涉及Android自定義控件的功能實(shí)現(xiàn)與布局相關(guān)技巧,需要的朋友可以參考下2016-01-01Android 8.0系統(tǒng)中應(yīng)用圖標(biāo)的適配微技巧
這篇文章主要介紹了Android 8.0系統(tǒng)中應(yīng)用圖標(biāo)的適配微技巧 ,需要的朋友可以參考下2018-04-04