版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Android實訓(xùn)案例(八)單機五子棋游戲,自定義棋盤,線條,棋子,游戲邏輯,游戲狀態(tài)存儲,再來一局一.棋盤我們一看就知道,我們必須自定義View,這里我們定義一個GameView來做游戲主類,第一步,先測量,我們這里不難知道,五子棋他的棋盤是一個正方形,所以我們需要去測量 /* * 測量 * * 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ù)測量模式細(xì)節(jié)處理 if (widthM
3、ode = MeasureSpec.UNSPECIFIED) width = hightSize; else if (hightMode = MeasureSpec.UNSPECIFIED) width = widthSize; /設(shè)置這樣就是一個正方形了 setMeasuredDimension(width, width); 這里的邏輯還是十分簡單的,我們拿到長和寬去比較一下,設(shè)置這個View的長寬Wie最小值,就是一個正方形了,所以我們的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è)置了一個半透明的紅色背景,是在我們調(diào)試的時候可以更加清晰的看清楚GameView的大小,所以,運行的結(jié)果二.線條這個應(yīng)該也算是棋盤的一部分吧,就是棋盤上的線條,我們應(yīng)該怎么去畫,首先,我們要去定義一些屬性 /線條數(shù)量 private static final int MAX_LINE = 10; /線條的寬度 private int mPanelWidth; /線條的高度 pri
6、vate float mLineHeight;然后,我們要去確定大小/* * 測量大小 * * 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)備一只畫筆,對吧,所以我們要初始化畫筆 /* * 初始化畫筆 */ private void initPaint() /設(shè)置顏色 mPaint.setColor(0x88000000); /抗鋸齒 mPaint.setAntiAlias(true); /設(shè)置防抖動 mPaint.setDither(true); /設(shè)置Style mPaint.setStyle(Paint.Style.STROKE); 現(xiàn)在我們可以去繪制了,我們在OnDraw(0方法里寫一個drawLine方法來專門繪制線條 /* * 繪制棋盤的方法 * * 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); 我們運行一下好的,這里,注意一下,我在activity_main.xml中定義了一個android:gravity="center"屬性,所以讓他居中,同樣的,我們在initPaint中加上點代碼讓我們看的更加直觀一點/設(shè)置顏色mPaint.setColor(Color.BLACK);/設(shè)置線條寬度mPaint.setStrokeWidth(3);同樣的,我們把構(gòu)造法里的設(shè)置背景的測試代碼注釋掉/測試代碼/setBackgro
10、undColor(0x44ff0000);這樣,我們運行一下得,我們現(xiàn)在有模有樣了三.棋子棋子我們事先準(zhǔn)備好了兩張圖片,但是這里我們要考慮他的大小的問題了,我們的思路是讓他是行高的四分之三大小,所以先聲明 /黑棋子 private Bitmap mBlack; /白棋子 private Bitmap mWhite;/比例,棋子的大小是高的四分之三 private float rowSize = 3 * 1.0f / 4;然后我們定義一個方法區(qū)初始化Bitmap /* * 初始化棋子 */ private void initBitmap() /拿到圖片資源 mBlack = BitmapFact
11、ory.decodeResource(getResources(), R.drawable.stone_black); mWhite = BitmapFactory.decodeResource(getResources(), R.drawable.stone_white); 拿到資源之后我們就可以設(shè)置大小了,我們在onSizeChanged()里面設(shè)置 /棋子寬度 int mWhiteWidth = (int) (mLineHeight * rowSize); /修改棋子大小 mWhite = Bitmap.createScaledBitmap(mWhite, mWhiteWidth, mW
12、hiteWidth, false); mBlack = Bitmap.createScaledBitmap(mBlack, mWhiteWidth, mWhiteWidth, false);不過棋子可沒我們想象的那么簡單,我們要點擊一下再去繪制一個棋子,這樣的思路該怎么去實現(xiàn)呢?我們實現(xià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(); /封裝成一個Point Point p = ge
14、tValidPoint(x, y); /判斷當(dāng)前這個點是否有棋子了 if(mWhiteArray.contains(p) | mBlackArray.contains(p) /點擊不生效 return false; /判斷如果是白子就存白棋集合,反之則黑棋集合 if (mIsWhite) mWhiteArray.add(p); else mBlackArray.add(p); /刷新 invalidate(); /改變值 mIsWhite = !mIsWhite; break; return true;這樣,有幾點是要說明一下的,首先我們new Point的時候為了避免重復(fù)繪制我們是實現(xiàn)了一個
15、方法/* * 不能重復(fù)點擊 * * param x * param y * return */ private Point getValidPoint(int x, int y) return new Point(int) (x / mLineHeight), (int) (y / mLineHeight); 緊接著我們就判斷,要是重復(fù)點擊,返回false,而且我們在action選擇也是選擇了ACTION_UP,為什么?為什么不是ACTION_DOWN?因為這個畢竟是一個View,父View會攔截(某些場景),所以我們選在UP上才是合情合理的好的,當(dāng)我們點擊之后就要繪制棋子了,這里我們也寫一個
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,我們實際運行一下四.游戲邏輯現(xiàn)在什么都有了,基本上都可用玩了,但是還少了重要的一點就是游戲結(jié)束,你到了五顆也需要判斷是否勝利呀,
18、對吧,我們寫一個方法,在每次繪制完成之后就去判斷是否有贏家 /* * 判斷是否勝利 */ private void checkWin() /判斷白棋是否有五個相同的棋子相連 boolean mWhiteWin = checkFiveLine(mWhiteArray); /判斷黑棋是否有五個相同的棋子相連 boolean mBlackWin = checkFiveLine(mBlackArray); /只要有一個勝利,游戲就結(jié)束 if (mWhiteWin | mBlackWin) mIsGameOver = true; mIsWhiteWin = mWhiteWin; Toast.makeTe
19、xt(getContext(), mIsWhiteWin ? "白棋勝利" : "黑棋勝利", Toast.LENGTH_SHORT).show(); 好的,我們重點邏輯就在checkFiveLine這個方法上了,這里,我們所知道的勝利有四種情況我們先定義一個常量 /勝利棋子數(shù)量 private static final int MAX_COUNT_IN_LINE = 5;OK,接下來我們可以實現(xiàn)以下勝利的邏輯了 /* * /判斷棋子是否有五個相同的棋子相連 * * 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; 我們不管哪個方向只要返回true就返回true,然后彈Toast,這里,四個方向的邏輯橫 /* * 判斷橫向的棋子 * * param x * param y * param points */ private boolean checkHorizontal(int x, int y, List<Point> points) /棋子標(biāo)記,記錄是否有五個 =1是因為自身是一個 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; /有五個就為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; /有五個就為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)記,記錄是否有五個 =1是因為自身是一個 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; /有五個就為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; /有五個就為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)記,記錄是否有五個 =1是因為自身是一個 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; /有五個就為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; /有五個就為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)記,記錄是否有五個 =1是因為自身是一個 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; /有五個就為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; /有五個就為true if (count = MAX_COUNT_IN_LINE) return true; return false; 這樣,我們運行一下嘿嘿,好玩吧!五.游戲狀態(tài)存儲這個就是當(dāng)我們游戲掛后臺之后,再回來游戲就沒了,我們應(yīng)該存儲他的狀態(tài),讓他每一次進(jìn)入的時候要是上一句沒有下完接著下,那我們該怎么去實現(xiàn)呢?和Activity一樣,我們View也有存儲狀態(tài)的方法 /* * 存儲狀態(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; /* * 重新運行 * * 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); 這樣就可以了,但是,有一點要知道,不要忘記在布局文件上給控件加上ID,不然狀態(tài)不會存儲哦 <com.lgl.fiverow.GameView andro
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五版智能航運物流船運輸合作協(xié)議合同2篇
- 二零二五年測繪數(shù)據(jù)處理與分析合同范本3篇
- 二零二五年特種花卉種子采購合同范本3篇
- 二零二五版商業(yè)街區(qū)保安臨時工勞動合同示范文本3篇
- 二零二五版生態(tài)農(nóng)業(yè)基地種植分包合同3篇
- 河北省二零二五年度二手房買賣合同附帶專業(yè)拆除及清理服務(wù)3篇
- 二零二五年度車輛過戶手續(xù)代理合同3篇
- 二零二五版汽車制造專用管子配件供應(yīng)合同3篇
- 二零二五年度酒店食堂承包服務(wù)合同范本3篇
- 二零二五年度礦業(yè)風(fēng)險評估與風(fēng)險管理合同2篇
- 割接方案的要點、難點及采取的相應(yīng)措施
- 2025年副護(hù)士長競聘演講稿(3篇)
- 2025至2031年中國臺式燃?xì)庠钚袠I(yè)投資前景及策略咨詢研究報告
- 原發(fā)性腎病綜合征護(hù)理
- 第三章第一節(jié)《多變的天氣》說課稿2023-2024學(xué)年人教版地理七年級上冊
- 2025年中國電科集團春季招聘高頻重點提升(共500題)附帶答案詳解
- 2025年度建筑施工現(xiàn)場安全管理合同2篇
- 建筑垃圾回收利用標(biāo)準(zhǔn)方案
- 2024年考研英語一閱讀理解80篇解析
- 福建省廈門市2023-2024學(xué)年高二上學(xué)期期末考試語文試題(解析版)
- 防火墻施工組織設(shè)計
評論
0/150
提交評論