版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年廣西演藝職業(yè)學(xué)院高職單招高職單招英語(yǔ)2016-2024歷年頻考點(diǎn)試題含答案解析
- 2025年廣州華商職業(yè)學(xué)院高職單招高職單招英語(yǔ)2016-2024歷年頻考點(diǎn)試題含答案解析
- 2025年廣東省外語(yǔ)藝術(shù)職業(yè)學(xué)院高職單招職業(yè)技能測(cè)試近5年常考版參考題庫(kù)含答案解析
- 2025年廣東工程職業(yè)技術(shù)學(xué)院高職單招職業(yè)技能測(cè)試近5年??及鎱⒖碱}庫(kù)含答案解析
- 2025年廣東南方職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性測(cè)試近5年??及鎱⒖碱}庫(kù)含答案解析
- 昆侖山黑海湖GDGTs化合物的現(xiàn)代過(guò)程調(diào)查及相關(guān)指標(biāo)的應(yīng)用潛力分析
- 2025年四川電力職業(yè)技術(shù)學(xué)院高職單招職業(yè)技能測(cè)試近5年??及鎱⒖碱}庫(kù)含答案解析
- 2025年中國(guó)直柄鉆市場(chǎng)調(diào)查研究報(bào)告
- 2025年呼和浩特職業(yè)學(xué)院高職單招職業(yè)技能測(cè)試近5年??及鎱⒖碱}庫(kù)含答案解析
- 2025年全球及中國(guó)制造業(yè)商業(yè)智能行業(yè)頭部企業(yè)市場(chǎng)占有率及排名調(diào)研報(bào)告
- 河南省濮陽(yáng)市2024-2025學(xué)年高一上學(xué)期1月期末考試語(yǔ)文試題(含答案)
- 割接方案的要點(diǎn)、難點(diǎn)及采取的相應(yīng)措施
- 2025年副護(hù)士長(zhǎng)競(jìng)聘演講稿(3篇)
- 2024年08月北京中信銀行北京分行社會(huì)招考(826)筆試歷年參考題庫(kù)附帶答案詳解
- 原發(fā)性腎病綜合征護(hù)理
- (一模)株洲市2025屆高三教學(xué)質(zhì)量統(tǒng)一檢測(cè) 英語(yǔ)試卷
- 基礎(chǔ)護(hù)理學(xué)導(dǎo)尿操作
- DB11∕T 1028-2021 民用建筑節(jié)能門窗工程技術(shù)標(biāo)準(zhǔn)
- (初級(jí))航空油料計(jì)量統(tǒng)計(jì)員技能鑒定理論考試題庫(kù)(含答案)
- 中國(guó)古代文學(xué)史 馬工程課件(中)24第六編 遼西夏金元文學(xué) 緒論
- 最新交管12123學(xué)法減分題庫(kù)含答案(通用版)
評(píng)論
0/150
提交評(píng)論