您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關如何在Android中通過自定義View實現一個五子棋游戲,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
GobangPanel棋盤面板:
public class GobangPanel extends View { private int mPanelWidth;//棋盤的寬度 private float mLineHeight;//行,高要為float private int MAX_LINE = 15;//棋盤行數 private int MAX_COUNT_IN_LINE = 5;//設置贏棋子個數(6子棋設置為6) private Paint mPaint = new Paint();//畫筆 private Bitmap mWhitePiece;//白色棋子 private Bitmap mBlackPiece;//黑色棋子 private float ratioPieceOfLineHeight = 3 * 1.0f / 4;//2個棋子間3/4距離 //白旗先手,當前輪到白棋了 private boolean mIsWhite = true; private ArrayList<Point> mWhiteArray = new ArrayList<>();//白棋數組 private List<Point> mBlackArray = new ArrayList<>();//黑騎數組 private boolean mIsGameOver;//游戲是否結束 private boolean mIsWhiteWinner;//白色棋子贏 true白子贏,false黑色贏 public GobangPanel(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * 初始化畫筆參數 */ private void init() { mPaint.setColor(0x88000000);//Paint顏色 半透明灰色 mPaint.setAntiAlias(true);//抗鋸齒(邊界明顯變模糊) mPaint.setDither(true);//設置防抖動(圖片柔和) mPaint.setStyle(Paint.Style.STROKE);//樣式 //黑、白棋資源圖片 mWhitePiece = BitmapFactory.decodeResource(getResources(), R.mipmap.white_bg); mBlackPiece = BitmapFactory.decodeResource(getResources(), R.mipmap.black_bg); } /** * 自定義View尺寸的規則 */ 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); } /** * 控件大小發生改變時調用 */ 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); } //觸摸焦點 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"; /** * 游戲結束方法 */ public void checkGameOver() { boolean whiteWin = checkFiveInLine(mWhiteArray); boolean blackWin = checkFiveInLine(mBlackArray); //黑棋或白棋贏游戲結束 if (whiteWin || blackWin) { mIsGameOver = true; mIsWhiteWinner = whiteWin; if (null != listener) { listener.onFinish(mIsWhiteWinner); Log.e(TAG, "checkGameOver: 111111" ); } Log.e(TAG, "checkGameOver: 222222" ); } } /** * 判斷棋子是否5個相鄰【5個相連只有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位置的棋子是否【水平】有相鄰的五個一致 */ private boolean checkLevel(int x, int y, List<Point> points) { int count = 1; //橫向左邊棋子個數 for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x - i, y))) { count++; } else { break; } } //有5個時則贏 if (count == MAX_COUNT_IN_LINE) return true; //橫向右邊棋子個數 for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x + i, y))) { count++; } else { break; } } //有5個時則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否[垂直]有相鄰的五個一致 */ private boolean checkVetical(int x, int y, List<Point> points) { int count = 1; //上下棋子個數 for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x, y - i))) { count++; } else { break; } } //有5個時則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x, y + i))) { count++; } else { break; } } //有5個時則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否【左斜和右斜】有相鄰的五個一致 */ private boolean checkLeftWin(int x, int y, List<Point> points) { int count = 1; //橫向上下棋子個數 for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x - i, y + i))) { count++; } else { break; } } //有5個時則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x + i, y - i))) { count++; } else { break; } } //有5個時則贏 if (count == MAX_COUNT_IN_LINE) return true; return false; } /** * 判斷x,y位置的棋子是否【右斜】有相鄰的五個一致 */ private boolean checkRightWin(int x, int y, List<Point> points) { int count = 1; //橫向上下棋子個數 for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x - i, y - i))) { count++; } else { break; } } //有5個時則贏,return true; if (count == MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i++) { //如果有加1,沒有重新計算是否有五個,否者中斷 if (points.contains(new Point(x + i, y + i))) { count++; } else { break; } } //有5個時則贏 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); } } /** * 再來一局 */ public void start() { if (null != mWhiteArray && null != mBlackArray) { mWhiteArray.clear();//清除數據 mBlackArray.clear(); } mIsGameOver = false; mIsWhiteWinner = 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"; /** * 保存數據 */ 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; } /** * 恢復時調用 */ 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); } /** * 游戲結束回調 */ 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("這是標題") .setMessage(mIsWhiteWinner ? "白棋勝利,是否重新開始?" : "黑棋勝利,是否重新開始?") //.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);按對話框以外的地方不起作用。按返回鍵起作用 //方法二:setCanceleable(false);按對話框以外的地方不起作用。按返回鍵也不起作用 .setCancelable(false) .create(); dialog.show(); } }
對應布局文件: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>
以上就是如何在Android中通過自定義View實現一個五子棋游戲,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。