Android實(shí)訓(xùn)案例(八)——單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局_第1頁(yè)
Android實(shí)訓(xùn)案例(八)——單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局_第2頁(yè)
Android實(shí)訓(xùn)案例(八)——單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局_第3頁(yè)
Android實(shí)訓(xùn)案例(八)——單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局_第4頁(yè)
Android實(shí)訓(xùn)案例(八)——單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局_第5頁(yè)
已閱讀5頁(yè),還剩14頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Android實(shí)訓(xùn)案例(八)單機(jī)五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲(chǔ),再來(lái)一局一.棋盤我們一看就知道,我們必須自定義View,這里我們定義一個(gè)GameView來(lái)做游戲主類,第一步,先測(cè)量,我們這里不難知道,五子棋他的棋盤是一個(gè)正方形,所以我們需要去測(cè)量 /* * 測(cè)量 * * param widthMeasureSpec * param heightMeasureSpec */ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) /獲取高寬值 int widthSiz

2、e = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int hightSize = MeasureSpec.getSize(heightMeasureSpec); int hightMode = MeasureSpec.getMode(heightMeasureSpec); /拿到寬和高的最小值,也就是寬 int width = Math.min(widthSize, heightMeasureSpec); /根據(jù)測(cè)量模式細(xì)節(jié)處理 if (widthM

3、ode = MeasureSpec.UNSPECIFIED) width = hightSize; else if (hightMode = MeasureSpec.UNSPECIFIED) width = widthSize; /設(shè)置這樣就是一個(gè)正方形了 setMeasuredDimension(width, width); 這里的邏輯還是十分簡(jiǎn)單的,我們拿到長(zhǎng)和寬去比較一下,設(shè)置這個(gè)View的長(zhǎng)寬Wie最小值,就是一個(gè)正方形了,所以我們的layout_main.xml是這樣寫的<?xml version="1.0" encoding="utf-8&quo

4、t;?><LinearLayout xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="drawable/main_bg" > <com.lgl.fiverow.GameView android:layout_width

5、="match_parent" android:layout_height="match_parent" /></LinearLayout>這里我在構(gòu)造方法中設(shè)置了一個(gè)半透明的紅色背景,是在我們調(diào)試的時(shí)候可以更加清晰的看清楚GameView的大小,所以,運(yùn)行的結(jié)果二.線條這個(gè)應(yīng)該也算是棋盤的一部分吧,就是棋盤上的線條,我們應(yīng)該怎么去畫,首先,我們要去定義一些屬性 /線條數(shù)量 private static final int MAX_LINE = 10; /線條的寬度 private int mPanelWidth; /線條的高度 pri

6、vate float mLineHeight;然后,我們要去確定大小/* * 測(cè)量大小 * * param w * param h * param oldw * param oldh */ 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; 不要著急,這些都只是一些準(zhǔn)備的工作,我們畫線條

7、是必須要在onDraw(0方法里的,但是前期我們要準(zhǔn)備一只畫筆,對(duì)吧,所以我們要初始化畫筆 /* * 初始化畫筆 */ private void initPaint() /設(shè)置顏色 mPaint.setColor(0x88000000); /抗鋸齒 mPaint.setAntiAlias(true); /設(shè)置防抖動(dòng) mPaint.setDither(true); /設(shè)置Style mPaint.setStyle(Paint.Style.STROKE); 現(xiàn)在我們可以去繪制了,我們?cè)贠nDraw(0方法里寫一個(gè)drawLine方法來(lái)專門繪制線條 /* * 繪制棋盤的方法 * * param ca

8、nvas */ private void drawLine(Canvas canvas) /獲取高寬 int w = mPanelWidth; float lineHeight = mLineHeight; /遍歷,繪制線條 for (int i = 0; i < MAX_LINE; i+) /橫坐標(biāo) int startX = (int) (lineHeight / 2); int endX = (int) (w - lineHeight / 2); /縱坐標(biāo) int y = (int) (0.5 + i) * lineHeight); /繪制橫 canvas.drawLine(star

9、tX, y, endX, y, mPaint); /繪制縱 canvas.drawLine(y, startX, y, endX, mPaint); 我們運(yùn)行一下好的,這里,注意一下,我在activity_main.xml中定義了一個(gè)android:gravity="center"屬性,所以讓他居中,同樣的,我們?cè)趇nitPaint中加上點(diǎn)代碼讓我們看的更加直觀一點(diǎn)/設(shè)置顏色mPaint.setColor(Color.BLACK);/設(shè)置線條寬度mPaint.setStrokeWidth(3);同樣的,我們把構(gòu)造法里的設(shè)置背景的測(cè)試代碼注釋掉/測(cè)試代碼/setBackgro

10、undColor(0x44ff0000);這樣,我們運(yùn)行一下得,我們現(xiàn)在有模有樣了三.棋子棋子我們事先準(zhǔn)備好了兩張圖片,但是這里我們要考慮他的大小的問(wèn)題了,我們的思路是讓他是行高的四分之三大小,所以先聲明 /黑棋子 private Bitmap mBlack; /白棋子 private Bitmap mWhite;/比例,棋子的大小是高的四分之三 private float rowSize = 3 * 1.0f / 4;然后我們定義一個(gè)方法區(qū)初始化Bitmap /* * 初始化棋子 */ private void initBitmap() /拿到圖片資源 mBlack = BitmapFact

11、ory.decodeResource(getResources(), R.drawable.stone_black); mWhite = BitmapFactory.decodeResource(getResources(), R.drawable.stone_white); 拿到資源之后我們就可以設(shè)置大小了,我們?cè)趏nSizeChanged()里面設(shè)置 /棋子寬度 int mWhiteWidth = (int) (mLineHeight * rowSize); /修改棋子大小 mWhite = Bitmap.createScaledBitmap(mWhite, mWhiteWidth, mW

12、hiteWidth, false); mBlack = Bitmap.createScaledBitmap(mBlack, mWhiteWidth, mWhiteWidth, false);不過(guò)棋子可沒(méi)我們想象的那么簡(jiǎn)單,我們要點(diǎn)擊一下再去繪制一個(gè)棋子,這樣的思路該怎么去實(shí)現(xiàn)呢?我們實(shí)現(xiàn)它的點(diǎn)擊事件,這里先定義幾個(gè)變量 /存儲(chǔ)用戶點(diǎn)擊的坐標(biāo) private List<Point> mWhiteArray = new ArrayList<>(); private List<Point> mBlackArray = new ArrayList<>()

13、; /標(biāo)記,是執(zhí)黑子還是白子 ,白棋先手 private boolean mIsWhite = true;這樣才和觸摸事件相得映彰 /* * 觸摸事件 * * param event * return */ Override public boolean onTouchEvent(MotionEvent event) switch (event.getAction() /按下事件 case MotionEvent.ACTION_UP: int x = (int) event.getX(); int y = (int) event.getY(); /封裝成一個(gè)Point Point p = ge

14、tValidPoint(x, y); /判斷當(dāng)前這個(gè)點(diǎn)是否有棋子了 if(mWhiteArray.contains(p) | mBlackArray.contains(p) /點(diǎn)擊不生效 return false; /判斷如果是白子就存白棋集合,反之則黑棋集合 if (mIsWhite) mWhiteArray.add(p); else mBlackArray.add(p); /刷新 invalidate(); /改變值 mIsWhite = !mIsWhite; break; return true;這樣,有幾點(diǎn)是要說(shuō)明一下的,首先我們new Point的時(shí)候?yàn)榱吮苊庵貜?fù)繪制我們是實(shí)現(xiàn)了一個(gè)

15、方法/* * 不能重復(fù)點(diǎn)擊 * * param x * param y * return */ private Point getValidPoint(int x, int y) return new Point(int) (x / mLineHeight), (int) (y / mLineHeight); 緊接著我們就判斷,要是重復(fù)點(diǎn)擊,返回false,而且我們?cè)赼ction選擇也是選擇了ACTION_UP,為什么?為什么不是ACTION_DOWN?因?yàn)檫@個(gè)畢竟是一個(gè)View,父View會(huì)攔截(某些場(chǎng)景),所以我們選在UP上才是合情合理的好的,當(dāng)我們點(diǎn)擊之后就要繪制棋子了,這里我們也寫一個(gè)

16、方法 /* * 繪制棋子的方法 * * param canvas */ private void drawPieces(Canvas canvas) for (int i = 0; i < mWhiteArray.size(); i+) /獲取白棋子的坐標(biāo) Point whitePoint = mWhiteArray.get(i); canvas.drawBitmap(mBlack, (whitePoint.x + (1 - rowSize) / 2) * mLineHeight, (whitePoint.y + (1 - rowSize) / 2) * mLineHeight, nul

17、l); for (int i = 0; i < mBlackArray.size(); i+) /獲取黑棋子的坐標(biāo) Point blackPoint = mBlackArray.get(i); canvas.drawBitmap(mWhite, (blackPoint.x + (1 - rowSize) / 2) * mLineHeight, (blackPoint.y + (1 - rowSize) / 2) * mLineHeight, null); OK,我們實(shí)際運(yùn)行一下四.游戲邏輯現(xiàn)在什么都有了,基本上都可用玩了,但是還少了重要的一點(diǎn)就是游戲結(jié)束,你到了五顆也需要判斷是否勝利呀,

18、對(duì)吧,我們寫一個(gè)方法,在每次繪制完成之后就去判斷是否有贏家 /* * 判斷是否勝利 */ private void checkWin() /判斷白棋是否有五個(gè)相同的棋子相連 boolean mWhiteWin = checkFiveLine(mWhiteArray); /判斷黑棋是否有五個(gè)相同的棋子相連 boolean mBlackWin = checkFiveLine(mBlackArray); /只要有一個(gè)勝利,游戲就結(jié)束 if (mWhiteWin | mBlackWin) mIsGameOver = true; mIsWhiteWin = mWhiteWin; Toast.makeTe

19、xt(getContext(), mIsWhiteWin ? "白棋勝利" : "黑棋勝利", Toast.LENGTH_SHORT).show(); 好的,我們重點(diǎn)邏輯就在checkFiveLine這個(gè)方法上了,這里,我們所知道的勝利有四種情況我們先定義一個(gè)常量 /勝利棋子數(shù)量 private static final int MAX_COUNT_IN_LINE = 5;OK,接下來(lái)我們可以實(shí)現(xiàn)以下勝利的邏輯了 /* * /判斷棋子是否有五個(gè)相同的棋子相連 * * param points * return */ private boolean che

20、ckFiveLine(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 = checkLeft(x, y, points); if (win)

21、 return true; /右斜 win = checkRight(x, y, points); if (win) return true; return false; 我們不管哪個(gè)方向只要返回true就返回true,然后彈Toast,這里,四個(gè)方向的邏輯橫 /* * 判斷橫向的棋子 * * param x * param y * param points */ private boolean checkHorizontal(int x, int y, List<Point> points) /棋子標(biāo)記,記錄是否有五個(gè) =1是因?yàn)樽陨硎且粋€(gè) int count = 1; /左 f

22、or (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x - i, y) count+; else break; /有五個(gè)就為true 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; /有五個(gè)就為true if (count

23、= MAX_COUNT_IN_LINE) return true; return false; 橫 /* * 判斷縱向的棋子 * * param x * param y * param points */ private boolean checkVertical(int x, int y, List<Point> points) /棋子標(biāo)記,記錄是否有五個(gè) =1是因?yàn)樽陨硎且粋€(gè) int count = 1; /上 for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x,

24、y - i) count+; else break; /有五個(gè)就為true 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; /有五個(gè)就為true if (count = MAX_COUNT_IN_LINE) return true; return false; 左斜 /* * 判斷左斜向的棋子 * * param x * para

25、m y * param points */ private boolean checkLeft(int x, int y, List<Point> points) /棋子標(biāo)記,記錄是否有五個(gè) =1是因?yàn)樽陨硎且粋€(gè) 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; /有五個(gè)就為true if (count = MAX_COUNT_IN_LINE) return true; fo

26、r (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x + i, y - i) count+; else break; /有五個(gè)就為true if (count = MAX_COUNT_IN_LINE) return true; return false; 右斜 /* * 判斷右斜向的棋子 * * param x * param y * param points */ private boolean checkRight(int x, int y, List<Point> po

27、ints) /棋子標(biāo)記,記錄是否有五個(gè) =1是因?yàn)樽陨硎且粋€(gè) int count = 1; for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x - i, y - i) unt+; else break; /有五個(gè)就為true 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

28、, y + i) count+; else break; /有五個(gè)就為true if (count = MAX_COUNT_IN_LINE) return true; return false; 這樣,我們運(yùn)行一下嘿嘿,好玩吧!五.游戲狀態(tài)存儲(chǔ)這個(gè)就是當(dāng)我們游戲掛后臺(tái)之后,再回來(lái)游戲就沒(méi)了,我們應(yīng)該存儲(chǔ)他的狀態(tài),讓他每一次進(jìn)入的時(shí)候要是上一句沒(méi)有下完接著下,那我們?cè)撛趺慈?shí)現(xiàn)呢?和Activity一樣,我們View也有存儲(chǔ)狀態(tài)的方法 /* * 存儲(chǔ)狀態(tài) * * return */ Override protected Parcelable onSaveInstanceState() Bundl

29、e bundle = new Bundle(); bundle.putParcelable(INSTANCE, super.onSaveInstanceState(); bundle.putBoolean(INSTANCE_GAMEOVER, mIsGameOver); bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY, mWhiteArray); bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY, mBlackArray); return bundle; /* * 重新運(yùn)行 * * par

30、am state */ Override protected void onRestoreInstanceState(Parcelable state) /取值 if (state instanceof Bundle) Bundle bundle = (Bundle) state; mIsGameOver = bundle.getBoolean(INSTANCE_GAMEOVER); mWhiteArray = bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY); mBlackArray = bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY); /調(diào)用 super.onRestoreInstanceState(bundle.getParcelable(INSTANCE); return; super.onRestoreInstanceState(state); 這樣就可以了,但是,有一點(diǎn)要知道,不要忘記在布局文件上給控件加上ID,不然狀態(tài)不會(huì)存儲(chǔ)哦 <com.lgl.fiverow.GameView andro

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論