Android自定義View實(shí)現(xiàn)五子棋游戲
本文實(shí)例為大家分享了Android五子棋游戲的具體代碼,供大家參考,具體內(nèi)容如下
1、效果圖:
2、GobangPanel棋盤(pán)面板:
public class GobangPanel extends View { private int mPanelWidth;//棋盤(pán)的寬度 private float mLineHeight;//行,高要為float private int MAX_LINE = 15;//棋盤(pán)行數(shù) private int MAX_COUNT_IN_LINE = 5;//設(shè)置贏棋子個(gè)數(shù)(6子棋設(shè)置為6) private Paint mPaint = new Paint();//畫(huà)筆 private Bitmap mWhitePiece;//白色棋子 private Bitmap mBlackPiece;//黑色棋子 private float ratioPieceOfLineHeight = 3 * 1.0f / 4;//2個(gè)棋子間3/4距離 //白旗先手,當(dāng)前輪到白棋了 private boolean mIsWhite = true; private ArrayList<Point> mWhiteArray = new ArrayList<>();//白棋數(shù)組 private List<Point> mBlackArray = new ArrayList<>();//黑騎數(shù)組 private boolean mIsGameOver;//游戲是否結(jié)束 private boolean mIsWhiteWinner;//白色棋子贏 true白子贏,false黑色贏 public GobangPanel(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * 初始化畫(huà)筆參數(shù) */ private void init() { mPaint.setColor(0x88000000);//Paint顏色 半透明灰色 mPaint.setAntiAlias(true);//抗鋸齒(邊界明顯變模糊) mPaint.setDither(true);//設(shè)置防抖動(dòng)(圖片柔和) mPaint.setStyle(Paint.Style.STROKE);//樣式 //黑、白棋資源圖片 mWhitePiece = BitmapFactory.decodeResource(getResources(), R.mipmap.white_bg); mBlackPiece = BitmapFactory.decodeResource(getResources(), R.mipmap.black_bg); } /** * 自定義View尺寸的規(guī)則 */ 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.max(widthSize, heightSize); //最大值 if (widthMode == MeasureSpec.UNSPECIFIED) { width = heightSize; } else if (heightMode == MeasureSpec.UNSPECIFIED) { width = widthSize; } setMeasuredDimension(width, width); } /** * 控件大小發(fā)生改變時(shí)調(diào)用 */ protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mPanelWidth = w;//棋盤(pán)的寬高 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); } //觸摸焦點(diǎn) 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 = getValidPoint(x, y); if (mWhiteArray.contains(p) || mBlackArray.contains(p)) { return false; } if (mIsWhite) { mWhiteArray.add(p); } else { mBlackArray.add(p); } invalidate();//重繪棋子 mIsWhite = !mIsWhite; } return true;//感興趣交給其處理 } private Point getValidPoint(int x, int y) { return new Point((int) (x / mLineHeight), (int) (y / mLineHeight)); } protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawBoard(canvas); drawPieces(canvas); checkGameOver(); } private static final String TAG = "GobangPanel"; /** * 游戲結(jié)束方法 */ public void checkGameOver() { boolean whiteWin = checkFiveInLine(mWhiteArray); boolean blackWin = checkFiveInLine(mBlackArray); //黑棋或白棋贏游戲結(jié)束 if (whiteWin || blackWin) { mIsGameOver = true; mIsWhiteWinner = whiteWin; if (null != listener) { listener.onFinish(mIsWhiteWinner); Log.e(TAG, "checkGameOver: 111111" ); } Log.e(TAG, "checkGameOver: 222222" ); } } /** * 判斷棋子是否5個(gè)相鄰【5個(gè)相連只有4中情況分別是:水平、垂直、左斜和右斜】 */ private boolean checkFiveInLine(List<Point> points) { for (Point p : points) { int x = p.x; int y = p.y; boolean win = checkLevel(x, y, points); if (win) return true; win = checkVetical(x, y, points); if (win) return true; win = checkLeftWin(x, y, points); if (win) return true; win = checkRightWin(x, y, points); if (win) return true; } return false; } /** * 判斷x,y位置的棋子是否【水平】有相鄰的五個(gè)一致 */ private boolean checkLevel(int x, int y, List<Point> points) { int count = 1; //橫向左邊棋子個(gè)數(shù) for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x - i, y))) { count++; } else { break; } } //有5個(gè)時(shí)則贏 if (count == MAX_COUNT_IN_LINE) return true; //橫向右邊棋子個(gè)數(shù) for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x + i, y))) { count++; } else { break; } } //有5個(gè)時(shí)則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否[垂直]有相鄰的五個(gè)一致 */ private boolean checkVetical(int x, int y, List<Point> points) { int count = 1; //上下棋子個(gè)數(shù) for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x, y - i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x, y + i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否【左斜和右斜】有相鄰的五個(gè)一致 */ private boolean checkLeftWin(int x, int y, List<Point> points) { int count = 1; //橫向上下棋子個(gè)數(shù) for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x - i, y + i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x + i, y - i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否【右斜】有相鄰的五個(gè)一致 */ private boolean checkRightWin(int x, int y, List<Point> points) { int count = 1; //橫向上下棋子個(gè)數(shù) for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x - i, y - i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒(méi)有重新計(jì)算是否有五個(gè),否者中斷 if (points.contains(new Point(x + i, y + i))) { count++; } else { break; } } //有5個(gè)時(shí)則贏 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); } } /** * 畫(huà)格子棋盤(pán) */ private void drawBoard(Canvas canvas) { int w = mPanelWidth; float lineHeight = mLineHeight; for (int i = 0; i < MAX_LINE; i++) { int startx = (int) (lineHeight / 2);//橫坐標(biāo)起點(diǎn),終點(diǎn) 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); } } /** * 再來(lái)一局 */ public void start() { if (null != mWhiteArray && null != mBlackArray) { mWhiteArray.clear();//清除數(shù)據(jù) mBlackArray.clear(); } mIsGameOver = false; mIsWhiteWinner = false; invalidate(); //再次調(diào)用 } /** * 后臺(tái)運(yùn)行時(shí),調(diào)用此方法,防止數(shù)據(jù)丟失 */ private static final String INSTANCE = "instance"; private static final String INSTANCE_GAME_OVER = "instance_game_over"; //游戲結(jié)束 private static final String INSTANCE_WHITE_ARRAY = "instance_white_array"; //白 private static final String INSTANCE_BLACK_ARRAY = "instance_black_array"; /** * 保存數(shù)據(jù) */ protected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(INSTANCE, super.onSaveInstanceState()); bundle.putBoolean(INSTANCE_GAME_OVER, mIsGameOver); bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY, mWhiteArray); bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY, mWhiteArray); return bundle; } /** * 恢復(fù)時(shí)調(diào)用 */ protected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; mIsGameOver = 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); } /** * 游戲結(jié)束回調(diào) */ public OnFinishListener listener; public void setListener(OnFinishListener listener) { this.listener = listener; } public interface OnFinishListener { void onFinish(boolean mIsWhiteWinner); } }
3、使用MainActivity
public class MainActivity extends AppCompatActivity { private GobangPanel panel; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); panel = this.findViewById(R.id.gobang_panel); panel.setListener(new GobangPanel.OnFinishListener() { @Override public void onFinish(boolean mIsWhiteWinner) { initDialog(mIsWhiteWinner); } }); } /** * 初始化彈框 */ private void initDialog(boolean mIsWhiteWinner) { AlertDialog dialog = new AlertDialog.Builder(this) //.setTitle("這是標(biāo)題") .setMessage(mIsWhiteWinner ? "白棋勝利,是否重新開(kāi)始?" : "黑棋勝利,是否重新開(kāi)始?") //.setIcon(R.mipmap.ic_launcher) .setPositiveButton("確定", new DialogInterface.OnClickListener() {//添加"Yes"按鈕 @Override public void onClick(DialogInterface dialogInterface, int i) { panel.start(); } }) // .setNegativeButton("取消", new DialogInterface.OnClickListener() {//添加取消 // @Override // public void onClick(DialogInterface dialogInterface, int i) { // Toast.makeText(MainActivity.this, "這是取消按鈕", Toast.LENGTH_SHORT).show(); // } // }) //方法一:setCanceledOnTouchOutside(false);按對(duì)話(huà)框以外的地方不起作用。按返回鍵起作用 //方法二:setCanceleable(false);按對(duì)話(huà)框以外的地方不起作用。按返回鍵也不起作用 .setCancelable(false) .create(); dialog.show(); } }
對(duì)應(yīng)布局文件:activity_main:
<HorizontalScrollView 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:background="#fff" tools:context=".MainActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <com.helloworld.game.GobangPanel android:id="@+id/gobang_panel" android:layout_width="1000dp" android:layout_height="1000dp" android:layout_centerInParent="true" /> </ScrollView> </HorizontalScrollView>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android實(shí)現(xiàn)五子棋游戲(局域網(wǎng)版)
- android自定義View實(shí)現(xiàn)簡(jiǎn)單五子棋游戲
- Android自定義view之圍棋動(dòng)畫(huà)效果的實(shí)現(xiàn)
- 基于android實(shí)現(xiàn)五子棋開(kāi)發(fā)
- Android自定義View實(shí)現(xiàn)五子棋小游戲
- android簡(jiǎn)單自定義View實(shí)現(xiàn)五子棋
- Android自定義View實(shí)現(xiàn)五子棋游戲
- Android開(kāi)發(fā)實(shí)現(xiàn)的簡(jiǎn)單五子棋游戲示例
- Android游戲開(kāi)發(fā)之黑白棋
- Android實(shí)現(xiàn)中國(guó)象棋游戲(局域網(wǎng)版)
相關(guān)文章
Android中Progress的簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android中Progress的簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05Android編輯框EditText與焦點(diǎn)變更監(jiān)視器及文本變化監(jiān)視器實(shí)現(xiàn)流程詳解
這篇文章主要介紹了Android編輯框EditText與焦點(diǎn)變更監(jiān)視器及文本變化監(jiān)視器實(shí)現(xiàn)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09Android矢量圖之VectorDrawable類(lèi)自由填充色彩
這篇文章主要介紹了Android矢量圖之VectorDrawable類(lèi)自由填充色彩的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-05-05Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁(yè)源碼查看器實(shí)例
這篇文章主要介紹了Android編程實(shí)現(xiàn)網(wǎng)絡(luò)圖片查看器和網(wǎng)頁(yè)源碼查看器,結(jié)合實(shí)例形式分析了Android針對(duì)網(wǎng)絡(luò)圖片及網(wǎng)頁(yè)的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-01-01Android 仿余額寶數(shù)字跳動(dòng)動(dòng)畫(huà)效果完整代碼
這篇文章主要介紹了Android 仿余額寶數(shù)字跳動(dòng)動(dòng)畫(huà)效果完整代碼,需要的朋友可以參考下2017-11-11Android studio 引用aar 進(jìn)行java開(kāi)發(fā)的操作步驟
這篇文章主要介紹了Android studio 引用aar 進(jìn)行java開(kāi)發(fā)的操作步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09Android中自定義水平進(jìn)度條樣式之黑色虛線(xiàn)
這篇文章主要介紹了Android中自定義水平進(jìn)度條樣式之黑色虛線(xiàn) 的相關(guān)資料,需要的朋友可以參考下2016-03-03android開(kāi)機(jī)自啟動(dòng)原理與實(shí)現(xiàn)案例(附源碼)
完成一下步驟后,啟動(dòng)一次程序,完成注冊(cè)。等下次手機(jī)開(kāi)機(jī)時(shí),該軟件即會(huì)自動(dòng)啟動(dòng),具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下哈2013-06-06