helloPe的android項目實戰之連連看—實現篇(一)

來源:互聯網
上載者:User

  在上一篇文章helloPe的android項目實戰之連連看—設計篇中,我們進行了對android中連連看的項目的設計,包括功能模組的劃分以及核心演算法的設計。此文章接上文對android平台連連看程式進入實現階段。在此項目中,根據上文中對於功能的分析,我們將實現以下類(下面即是工程的檔案目錄):

                                        

在開發中,我們遵循由下向上的方式,也就是說,我們首先開發位於最底層的類,這種類並不依賴於其他的我們需要實現的類。根據上文的分析,首先我們開發在展示層模組中的介面顯示類,首先是BoardView類,在android平台下,採用繼承自View類的方式,看此類的代碼,代碼中盡量添加了詳細的注釋:

package nate.llk.view;/*匯入包種種再次略去*/
/** * ********************************************** * @author HelloPe ************************************************ */public class BoardView extends View {/** * xCount x軸方向的表徵圖數+2 */protected static final int xCount = 10;/** * yCount y軸方向的圖表數+2 */protected static final int yCount = 12;/** * map 連連看遊戲棋盤,map中添加的int型在程式中的意思是index,而不是螢幕座標! */protected int[][] map = new int[xCount][yCount];/** * iconSize 表徵圖大小,表徵圖是正方形,所以一個int變數表示即可 */protected int iconSize;/** * iconCounts 表徵圖的數目 */protected int iconCounts=19;/** * icons 所有的圖片 */protected Bitmap[] icons = new Bitmap[iconCounts];/** * path 可以連通點的路徑 */private Point[] path = null;/** * selected 選中的表徵圖 */protected List<Point> selected = new ArrayList<Point>();/** * 建構函式 * @param context * @param attrs */public BoardView(Context context, AttributeSet attrs) {super(context, attrs);calIconSize();Resources r = getResources();//載入連連看中的表徵圖資源loadBitmaps(1, r.getDrawable(R.drawable.fruit_01));loadBitmaps(2, r.getDrawable(R.drawable.fruit_02));loadBitmaps(3, r.getDrawable(R.drawable.fruit_03));loadBitmaps(4, r.getDrawable(R.drawable.fruit_04));loadBitmaps(5, r.getDrawable(R.drawable.fruit_05));loadBitmaps(6, r.getDrawable(R.drawable.fruit_06));loadBitmaps(7, r.getDrawable(R.drawable.fruit_07));loadBitmaps(8, r.getDrawable(R.drawable.fruit_08));loadBitmaps(9, r.getDrawable(R.drawable.fruit_09));loadBitmaps(10, r.getDrawable(R.drawable.fruit_10));loadBitmaps(11, r.getDrawable(R.drawable.fruit_11));loadBitmaps(12, r.getDrawable(R.drawable.fruit_12));loadBitmaps(13, r.getDrawable(R.drawable.fruit_13));loadBitmaps(14, r.getDrawable(R.drawable.fruit_14));loadBitmaps(15, r.getDrawable(R.drawable.fruit_15));loadBitmaps(16, r.getDrawable(R.drawable.fruit_17));loadBitmaps(17, r.getDrawable(R.drawable.fruit_18));loadBitmaps(18, r.getDrawable(R.drawable.fruit_19));}/** * 計算表徵圖的大小 */private void calIconSize(){//取得螢幕的大小DisplayMetrics dm = new DisplayMetrics();        ((Activity) this.getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm);        iconSize = dm.widthPixels/( xCount );}/** * 函數目的在於載入表徵圖資源,同時將一個key(特定的整數標識)與一個表徵圖進行綁定 * @param key 特定表徵圖的標識 * @param d drawable下的資源 */public void loadBitmaps(int key,Drawable d){Bitmap bitmap = Bitmap.createBitmap(iconSize,iconSize,Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);d.setBounds(0, 0, iconSize, iconSize);d.draw(canvas);icons[key]=bitmap;  //未用0 號index}/** * View內建的,但是在此方法中,有畫路徑(刪除聯通的兩個表徵圖), * 繪製棋盤的所有表徵圖(也可理解為重新整理,只要此map位置值>0) * 放大第一個選中的表徵圖(selected.size() == 1) */@Overrideprotected void onDraw(Canvas canvas) {/** * 繪製連通路徑,然後將路徑以及兩個表徵圖清除 */if(path != null && path.length >= 2){for(int i = 0; i < path.length - 1;++i){Paint paint = new Paint();paint.setColor(Color.BLUE);paint.setStrokeWidth(3);paint.setStyle(Paint.Style.STROKE);Point p1 = indexToScreen(path[i].x,path[i].y);Point p2 = indexToScreen(path[i + 1].x,path[i + 1].y);canvas.drawLine(p1.x + iconSize/2, p1.y + iconSize/2, p2.x + iconSize/2, p2.y + iconSize/2, paint);}map[path[0].x][path[0].y] = 0;map[path[path.length - 1].x][path[path.length -1].y] = 0;selected.clear();path = null;}/** * 繪製棋盤的所有表徵圖 當這個座標內的值大於0時繪製 */for(int x = 1;x < xCount - 1; ++x){for(int y = 1; y < yCount -1; ++y){if(map[x][y]>0){Point p = indexToScreen(x, y);canvas.drawBitmap(icons[map[x][y]], p.x,p.y,null);}}}/** * 繪製選中表徵圖,當選中時表徵圖放大顯示 *///for(Point position:selected){if(selected.size() > 0){Point position = selected.get(0);Point p = indexToScreen(position.x, position.y);if(map[position.x][position.y] >= 1){canvas.drawBitmap(icons[map[position.x][position.y]],null,new Rect(p.x-5, p.y-5, p.x + iconSize + 5, p.y + iconSize + 5), null);}}super.onDraw(canvas);}/** * 工具方法 * @param x 數組中的橫座標 * @param y 數組中的縱座標 * @return 將表徵圖在數組中的座標轉成在螢幕上的真實座標 */public Point indexToScreen(int x,int y){return new Point(x * iconSize,y * iconSize);}/** * 工具方法 * @param x 螢幕中的橫座標 * @param y 螢幕中的縱座標 * @return 將表徵圖在螢幕中的座標轉成在數組上的虛擬座標 */public Point screenToIndex(int x,int y){int xindex = x / iconSize;int yindex = y / iconSize;if(xindex < xCount && yindex < yCount){return new Point(xindex,yindex);}else{return new Point(0,0);}}/** * 傳進來path資料更新顯示,也就是將能夠串連的表徵圖消除 * @param path */public void drawLine(Point[] path) {this.path = path;this.invalidate();}}

此類當中,主要是實現了將連連看表徵圖資源的載入並且使之與一個特定的int型key相綁定,所以在後面的對於表徵圖的貼圖,我們能夠更加方便的操作。當然

此類中還需要存在一些必要的工具函數,比如說screenToIndex方法等,因為我們是自訂View在螢幕上繪圖,需要用到螢幕座標,但是同時,連連看遊戲

中,我們還需要知道表徵圖的索引(由於表徵圖都是等長等寬,容易實現螢幕座標與index索引之間的轉換),以使方便操作。當然,此類中最重要的還是重寫

的onDraw函數;此函數中首先判斷path是否為null並且是否兩個及以上的元素,我們之前定義path變數時,是將其作為儲存連通路徑的工具。(path中

的值也就是連通路徑我們將在串連演算法實現時中加入)這裡我們首先在onDraw函數中繪製出線條(如果連通),隨後將路徑的首尾中的map值設為0,程

序中,第0行與最後一行map值始終為0,第0列與最後一列map值始終為0,map中的值0為0代表此處已經沒有了表徵圖,根據前面與表徵圖資源的綁定值與

map中的值對應,map中的值為幾則在相應的index上貼上相應的表徵圖。在onDraw函數中,還有一個功能就是將選擇的第一個表徵圖放大,以提醒玩家。

最後繪製(貼圖),如前面所說,map值為多少就在對應位置貼上相應的表徵圖資源,有前面載入資源時可知並沒有對應於0的表徵圖資源,為0時即不貼圖。

為了防止代碼混亂,上面的BoardView 類並沒有實現全部的功能,如touch事件的監聽,串連演算法的實現,判斷是否無解等等。所以我們將BoardView

類進行擴充,繼承BoardView的GameView(這樣做也使代碼不至於太混亂)。限於篇幅,我們可以先將GameView中用於監聽剩餘時間的內部類實現

(該類實現了Runnable介面):

/** * 用於更新剩餘時間的線程 * @author helloPe * */class RefreshTime implements Runnable{@Overridepublic void run() {if(isContinue){while(leftTime > 0 && !isStop){timerListener.onTimer(leftTime);leftTime --;try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}if(isStop && leftTime > 0){if(win());//setMode(WIN);elsesetMode(PAUSE);}//setMode(LOSE);else if(leftTime == 0){setMode(LOSE);}}}/** * 停止顯示的時間 */public void stopTimer(){isStop = true;isContinue = false;}/** * 設定繼續 */public void setContinue(){isContinue = true;isStop = false;refreshTime = new RefreshTime();Thread t = new Thread(refreshTime);    //注意正確啟動一個實現Runnable介面的線程t.start();}

上面已經提過,此線程用於控制遊戲的時間。

在此,再介紹自訂的幾個介面,

public interface OnStateListener{public void OnStateChanged(int StateMode);}

只含有一個方法,主要對於遊戲狀態的變換的監聽,比如pause,stop等等。

public interface OnTimerListener{public void onTimer(int leftTime);}

用於監聽剩餘時間,與上麵線程不同的是,此方法中利用上麵線程的leftTime的結果,主要用於更新遊戲中用於提醒玩家的時間進度條。

public interface OnToolsChangeListener{public void onRefreshChanged(int count);public void onTipChanged(int count);}

tool即是我們的遊戲中提供給玩家的兩個工具,一個是refresh一下遊戲介面,即將現有的棋盤重新打亂(當然,現有圖表數量不變),另一個是之前提過的hint的自動協助功能,協助玩家找到一組能夠連通的表徵圖。當然,這兩種工具都有次數的限制。

  BoardView類及時間軸程類的開發與介紹到此,後面我們將完整的實現遊戲棋盤的繪製與touch事件的處理,以及遊戲核心演算法中串連演算法、hint自動協助演算法與判斷是否無解演算法的實現。這些代碼的處理都在繼承自BoardView類的GameView類中。

  之所以寫本系列的文章,為了記錄android小項目的經曆,增加實戰的能力,做個總結。並不是為了做出多麼新穎的項目,當然也是向不少的網友學習了的!


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.