亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

瀏覽:3日期:2023-12-14 15:52:38
目錄一、項目概述二、開發環境三、需求分析四、實現過程1、拼圖游戲布局繪制2、拼圖游戲時間計時3、拼圖游戲打亂顯示4、拼圖游戲碎片位置切換5、拼圖游戲成功的條件6、拼圖游戲重新開始五、運行效果六、項目總結七、項目源碼一、項目概述

之前有不少粉絲私信我說,能不能用Android原生的語言開發一款在手機上運行的游戲呢?

說實話,使用java語言直接開發游戲這個需求有點難,因為一些比較復雜的游戲都是通過cocos2D或者Unity3D等游戲引擎開發出來的,然后再移植到Android手機當中,使用完整的游戲引擎開發的過程比較簡單,而且界面比較流暢,觀感和體驗度都很好。

所以直接使用java開發的游戲并不多。當然,雖說不多但也有。簡單些的比如:2048、拼圖游戲、貪吃蛇、推箱子等,復雜點的比如:斗地主,這些都可以用java語言開發。因為這些游戲刷新界面次數比較少,是可以用java開發出來的。

所以在這篇博客里面,我們就來開發一款簡單的拼圖游戲,這款拼圖游戲就和我們小時候玩的游戲是一樣的,這里面的涉及到的算法不多,可以很容易學會,是作為入門Android的一個非常好的實例。

二、開發環境

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

三、需求分析

我們先來看下最終要實現的效果:

可以看到游戲開始后,開始計時,然后下面是被打亂的九宮格圖片,最后一塊是空白的,因為要留出空間移動,中間是重新開始按鈕,點擊就會重新計時而且拼圖碎片重新打亂,最底下是原圖,方便大家對照著進行拼湊。當你拼圖完成后,上面的第九塊拼圖會立刻顯示出來補齊整張圖片,然后彈出對話框,告訴你拼圖成功,用時為多少多少秒,點擊確認即可。Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

所以我們分為六個步驟來實現:

拼圖游戲布局繪制 拼圖游戲時間計時 拼圖游戲打亂顯示 拼圖游戲碎片位置切換 拼圖游戲成功的條件 拼圖游戲重新開始

我們來看下需要準備的圖片素材:

這里先是一張小熊的樣圖,命名就是yangtu。然后就是將它按九宮格裁剪成的九張圖片,命名格式我來解釋下:我們看第八張我選中的圖片,它的名字為img_xiaoxiong_02x01。這里解釋下為什么是02x01,這就可以看做一個三行三列的二維數組,排列方式就和下面一樣。數組行和列下標都是從0開始,所以第八張就是在第2行第1列,所以就是02x01,其他的也以此類推。大家可以自己選圖片進行裁剪命名,當然也可以直接下載我的源碼,里面就有這些圖片。

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

下面我們就一起來實現這個拼圖游戲吧~

四、實現過程1、拼圖游戲布局繪制

我們首先來分析下游戲的layout布局

再來看下最終實現的效果圖,先分析一下怎么繪制布局,實現一個項目的第一步是將布局按照自己期望的樣子完成。

因為這是一個上下結構,所以我們用一個線性布局(LinearLayout)來實現最合適,方向(orientation)設置為豎直方向(vertical)。可以看到這個拼圖分為三行三列,所以我們直接將每一行分為一個小的LinearLayout,一共三個,然后在每個小的LinearLayout里面水平放三個圖片按鈕,這樣就實現了,思路有了,我們來繪制吧。

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

我們來繪制游戲的layout布局

從上至下的第一個布局是顯示時間的TextView,我們將它的id設置為pt_tv_time,layout_width和layout_height都設置為wrap_content,就是適應內容大小,然后text文本內容設為“時間:0”,這個是方便測試寫上文本的,因為邊寫代碼可以邊看旁邊的效果變化。

然后layout_gravity設置為'center',就是設置自己在父容器(頂層的LinearLayout)中居中,這里補充下知識點:

gravity是設置自身內部元素的對齊方式。比如一個TextView,則是設置內部文字的對齊方式。如果是ViewGroup組件如LinearLayout的話,則為設置它內部view組件的對齊方式。 layout_gravity是設置自身相當于父容器的對齊方式。比如,一個TextView設置layout_gravity屬性,則表示這TextView相對于父容器的對齊方式。

再來改變下字體大小,設置textSize為20sp,sp是像素,補充下單位的知識點:

dp: device independent pixels(設備獨立像素),不同設備有不同的顯示效果,和設備硬件有關。 px: pixels(像素).,不同設備顯示效果相同,這個用的比較多。 pt: point,是一個標準的長度單位,1pt=1/72英寸,用于印刷業,非常簡單易用。 sp: scaled pixels(放大像素),主要用于字體顯示best for textsize。

最后設置字體顏色為#FF0000,即紅色。一般是通過colors.xml資源來引用,這里因為紅色比較好表示就直接設置了。

TextView代碼如下:

<TextViewandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:text='時間 : 0'android:layout_gravity='center'android:textSize='20sp'android:textColor='#FF0000'/>

設置完成后,我們來看下效果圖:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

接著我們來繪制九宮格拼圖,先設置第一行這三個小圖片的外布局,依然是LinearLayout,設置它的id='@+id/pt_line1',就表示第一行。

orientation選擇的是水平方向,因為每一行是水平放置的,layout_gravity設置為'center',表示居中,代碼如下。

<LinearLayoutandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:orientation='horizontal'android:layout_gravity='center'></LinearLayout>

設置第一張圖片,選擇的控件是ImageButton,顧名思義:圖片按鈕,正常按鈕就規規矩矩的,而圖片按鈕就很好看,一張圖片也可以進行點擊,這里設置它的id='@+id/pt_ib_00x00',方便在MainActivity里面調用。

00x00不用我多說了吧,上面解釋過了,將九宮格看成3X3的二維數組,那么行列下標就是0行0列,這里每行數和列數都用2位數字表示而已。

設置src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x00',就是將我們剛剛準備的圖片資源復制到這個mipmap文件夾中進行引用,每個id編號和圖片的名稱是對應的。

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

再設置個onClick方法,方法名為'onClick',我們后面會在MainActivity里面進行編寫點擊事件。第一張圖片的代碼如下:

<ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x00' android:padding='0dp' android:onClick='onClick'/>

依次類推,第二張和第三張圖片,我只要改下id和src就可以了,所以直接放上第一個小LinearLayout的代碼:

<LinearLayoutandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:orientation='horizontal'android:layout_gravity='center'><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x00' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x01' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x02' android:padding='0dp' android:onClick='onClick'/> </LinearLayout>

來看下顯示效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

那第二行和第三行是不是也一樣照葫蘆畫瓢,沒錯,直接復制第一行的代碼,然后修改id和src就行。這里直接給出三個LinearLayout的代碼:

<LinearLayoutandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:orientation='horizontal'android:layout_gravity='center'><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x00' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x01' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_00x02' android:padding='0dp' android:onClick='onClick'/> </LinearLayout> <LinearLayoutandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:orientation='horizontal'android:layout_gravity='center'><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_01x00' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_01x01' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_01x02' android:padding='0dp' android:onClick='onClick'/> </LinearLayout> <LinearLayoutandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:orientation='horizontal'android:layout_gravity='center'><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_02x00' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_02x01' android:padding='0dp' android:onClick='onClick'/><ImageButton android: android:layout_width='wrap_content' android:layout_height='wrap_content' android:src='http://www.aoyou183.cn/bcjs/@mipmap/img_xiaoxiong_02x02' android:padding='0dp' android:onClick='onClick' android:visibility='invisible'/> </LinearLayout>

有一點需要注意的,不知道有沒有同學發現——第三行的第三張圖片,也就是右下角的那張圖片,它有個屬性,其他的圖片都沒有:visibility=“invisible”,這是干什么的呢?

這個其實就是設置控件是否可見,默認情況下控件都是可見的(visible),只有設置visibility='invisible'后,這個控件才不顯示出來,我們來看下整體效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

OK,九宮格完成后,下面是一個重新開始的Button。

這個比較簡單了,主要設置了onClick=“restart”,這個后面會在MainActivity里面編寫重新開始游戲的邏輯,還設置了android:layout_marginTop=“20dp”,這是設置此控件與上面控件邊距相隔20dp,為了和九宮格保持一定間距,代碼如下:

<Buttonandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:onClick='restart'android:layout_gravity='center'android:text='重新開始'android:layout_marginTop='20dp'/>

顯示效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

最后就是我們的樣圖了,有了我們上面的經驗,這個應該很容易就畫出來了,放置圖片的控件我們一般使用ImageView,然后設置src='http://www.aoyou183.cn/bcjs/@mipmap/yangtu',就顯示了我們的樣圖,最后為了保持距離美,設置layout_marginTop=“20dp”,代碼如下:

<ImageViewandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:layout_gravity='center'android:src='http://www.aoyou183.cn/bcjs/@mipmap/yangtu'android:layout_marginTop='20dp'/>

好了,我們來看下效果圖:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

至此,我們的布局就繪制完成了!

我們來編寫下MainActivity的基本框架

可以先來看下什么都沒有的MainActivity。里面只有onClick()和restart()兩個新的方法,這是在上面布局中設置的方法,onClick是圖片按鈕的點擊事件,restart是重新開始按鈕的點擊事件,這兩個方法的具體實現邏輯會在下面講到。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);// 設置要顯示的視圖 setContentView(R.layout.activity_main);}// 圖片按鈕的點擊事件 public void onClick(View view) {}/* 重新開始按鈕的點擊事件*/ public void restart(View view) { }}

這里我們要做的是把所有在布局中用到的控件定義好,然后初始化這些控件

先來定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標,一個重啟按鈕和一個顯示時間的文本框

// 定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標 ImageButton ib00,ib01,ib02,ib10,ib11,ib12,ib20,ib21,ib22;// 一個重啟按鈕 Button restartBtn;// 一個顯示時間的文本框 TextView timeTv;

然后我們在onCreate中定義一個initView()方法,這個方法是用來初始化控件的

// 初始化layout控件的方法initView();

然后創建該方法,在該方法里面初始化定義的控件,通過findViewById()進行綁定控件,將聲明的變量和layout中對應的控件進行綁定,實現引用的效果,代碼如下:

/* 初始化控件:綁定9個圖片按鈕,1個顯示時間的文本框,1個重啟按鈕*/ private void initView() {ib00 = findViewById(R.id.pt_ib_00x00);ib01 = findViewById(R.id.pt_ib_00x01);ib02 = findViewById(R.id.pt_ib_00x02);ib10 = findViewById(R.id.pt_ib_01x00);ib11 = findViewById(R.id.pt_ib_01x01);ib12 = findViewById(R.id.pt_ib_01x02);ib20 = findViewById(R.id.pt_ib_02x00);ib21 = findViewById(R.id.pt_ib_02x01);ib22 = findViewById(R.id.pt_ib_02x02);timeTv = findViewById(R.id.pt_tv_time);restartBtn = findViewById(R.id.pt_btn_restart); }

初始化的完整代碼,可以作為模板:

public class MainActivity extends AppCompatActivity {// 定義九個圖片按鈕,命名方法也是00,01這樣的橫縱坐標 ImageButton ib00,ib01,ib02,ib10,ib11,ib12,ib20,ib21,ib22;// 一個重啟按鈕 Button restartBtn;// 一個顯示時間的文本框 TextView timeTv;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);// 設置要顯示的視圖 setContentView(R.layout.activity_main); initView();}private void initView() {ib00 = findViewById(R.id.pt_ib_00x00);ib01 = findViewById(R.id.pt_ib_00x01);ib02 = findViewById(R.id.pt_ib_00x02);ib10 = findViewById(R.id.pt_ib_01x00);ib11 = findViewById(R.id.pt_ib_01x01);ib12 = findViewById(R.id.pt_ib_01x02);ib20 = findViewById(R.id.pt_ib_02x00);ib21 = findViewById(R.id.pt_ib_02x01);ib22 = findViewById(R.id.pt_ib_02x02);timeTv = findViewById(R.id.pt_tv_time);restartBtn = findViewById(R.id.pt_btn_restart); }// 圖片按鈕的點擊事件 public void onClick(View view) {}/* 重新開始按鈕的點擊事件*/ public void restart(View view) { }} 2、拼圖游戲時間計時

完成基本工作后,我們思考下——如何實現時間的計時操作,這就相當于計時器的功能。這里我們可以用Handler消息機制來實現,補充下知識點:

Handler:作用就是發送與處理信息 Message:Handler接收與處理的消息對象

當我們的子線程想修改Activity中的UI組件時,我們可以新建一個Handler對象,通過這個對象向主線程發送信息;而我們發送的信息會先到主線程的MessageQueue進行等待,由Looper按先入先出順序取出,再根據message對象的what屬性分發給對應的Handler進行處理!

簡單來說:Handler就是用來發送消息和處理消息的一種機制,上面這段話可能聽起來有些懵,不過沒關系,其實沒有這么深奧,下面會讓大家明白怎么使用它來實現計時的。

先定義個時間變量,初值為0,因為從0開始計時

// 定義計數時間的變量 int time = 0;

然后定義發送和處理消息的對象handler,我們來重寫handleMessage方法,在方法里面我們進行了if判斷,如果這條消息的what值為1,那么時間time就+1,然后timeTv顯示時間為time秒,然后繼續向自己發送消息。

handler.sendEmptyMessageDelayed(1,1000)這句話的意思就是:延時1000毫秒后發送參數what為1的空信息,這樣它自己就能循環接收自己發的消息,實現計時的功能了,就這么簡單。

當然最開始要發送它一條消息,讓它這個方法運轉起來,我們在onCreate這個方法里面加上了一條handler.sendEmptyMessageDelayed(1,1000); 這樣在游戲一開始過了1s,handler就發送了一條what為1的空消息。然后它自己又立馬接收到了,進行時間加1,又自己發送給自己消息,實現計時!

這是定義的handler的代碼:

// 定義發送和處理消息的對象handler Handler handler = new Handler(){@Override// 重寫handleMessage方法,根據msg中what的值判斷是否執行后續操作public void handleMessage(Message msg) { if (msg.what==1) {time++;timeTv.setText('時間 : '+time+' 秒');// 指定延時1000毫秒后發送參數what為1的空信息handler.sendEmptyMessageDelayed(1,1000); }} };

這是在onCreate方法里面定義的一條消息

handler.sendEmptyMessageDelayed(1,1000);

我們來看下運行效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

除此之外,我們還需要在重新開始游戲后進行重新計時,這里又要怎么實現呢?

這里我們只需要在restart方法里面先停止handler的消息發送,保證時間不會再繼續+1了,然后將時間重新歸0,顯示當前時間,最后每隔1s發送參數what為1的消息msg,這樣就實現了重新開始計時,代碼如下:

/* 重新開始按鈕的點擊事件*/ public void restart(View view) {// 停止handler的消息發送handler.removeMessages(1);// 將時間重新歸0,并且重新開始計時time = 0;timeTv.setText('時間 : '+time+' 秒');// 每隔1s發送參數what為1的消息msghandler.sendEmptyMessageDelayed(1,1000); }

點擊重新開始后的實現效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

至此,我們的計時功能就實現了!

3、拼圖游戲打亂顯示

首先定義一個image數組,里面存放每張碎片(九宮格圖片)的id,int型數組是可以存放圖片的id的,但是不能存放圖片,注意這個區別。

// 將每張碎片的id存放到數組中,便于進行統一的管理,int型數組存放的肯定是int型變量 private int[]image = {R.mipmap.img_xiaoxiong_00x00,R.mipmap.img_xiaoxiong_00x01,R.mipmap.img_xiaoxiong_00x02,R.mipmap.img_xiaoxiong_01x00,R.mipmap.img_xiaoxiong_01x01,R.mipmap.img_xiaoxiong_01x02, R.mipmap.img_xiaoxiong_02x00,R.mipmap.img_xiaoxiong_02x01,R.mipmap.img_xiaoxiong_02x02};

再聲明一個imageIndex數組,它來存放上面圖片數組的下標,一共九張圖片,所以下標為0-8,它存儲的也就是0-8。我們為了讓上面九張圖片被打亂,所以,這里的下標等下會被打亂。

// 聲明上面圖片數組下標的數組,隨機排列這個數組,九張圖片,下標為0-8 private int[]imageIndex = new int[image.length];

下面我們寫一個函數disruptRandom( ),來實現進入游戲拼圖就打亂顯示的效果

先給下標數組每個元素賦值,下標是i,值就為i,就是imageIndex[i] = i。

// 給下標數組每個元素賦值,下標是i,值就為ifor (int i = 0; i < imageIndex.length; i++) { imageIndex[i] = i;}

然后進行20次for循環,隨機選擇兩個角標對應的值進行交換。先定義兩個角標rand1和rand2,rand1 = (int)(Math.random()*(imageIndex.length-1));這里我來重點解釋一下:Math.random()產生的隨機數為0~1之間的小數 此處說的0~1是包含左不包含右,即包含0不包含1!

ps:我在這里卡了2h至少,因為這個小細節點沒注意到,所以一定不能想當然,要查資料以求準確。

Math.random()的值域為[0,1),然后imageIndex.length-1就是8其實,*8那就是[0,8),再int取整最終值域為{0,1,2,3,4,5,6,7},因為int取整只會取整數位,不會四舍五入!

再用do-while循環實現了rand2的生成,之所以在do-while里面生成rand2,是為了判斷二次生成的角標和第一次是否相同,不同則break立刻跳出循環,執行swap交換;若第二次生成的與第一次相同,則重新進入do-while循環生成rand2,這部分代碼如下:

//規定20次,隨機選擇兩個角標對應的值進行交換int rand1,rand2;for (int j = 0; j < 20; j++) {// 隨機生成第一個角標// Math.random()產生的隨機數為0~1之間的小數 此處說的0~1是包含左不包含右,即包含0不包含1// Math.random()的值域為[0,1),然后*8就是[0,8),再int取整最終值域為{0,1,2,3,4,5,,6,7} rand1 = (int)(Math.random()*(imageIndex.length-1));// 第二次隨機生成的角標,不能和第一次隨機生成的角標相同,如果相同,就不方便交換了 do {rand2 = (int)(Math.random()*(imageIndex.length-1));// 判斷第一次和第二次生成的角標是否相同,不同則break立刻跳出循環,執行swap交換if (rand1!=rand2) { break;}// 若第二次生成的與第一次相同,則重新進入do-while循環生成rand2 }while (true); swap(rand1,rand2); }

這里的swap方法很簡單,就是交換兩個數的值,只不過這里參數是數組的下標:

// 交換數組指定角標(0-7這八個自然數)上的數據 private void swap(int rand1, int rand2) {int temp = imageIndex[rand1];imageIndex[rand1] = imageIndex[rand2];imageIndex[rand2] = temp; }

這里有個整個游戲的一個核心點:我們打亂的拼圖下標是{0,1,2,3,4,5,6,7}這八個,第九張拼圖的下標是不參與打亂的,有同學問為什么?是因為第九張圖片是不顯示出來的,而且不會參與到拼圖中,所以我們是將第九個圖片按鈕就設置成第九張圖片,然后invisible。

最后我們將每個圖片按鈕設置圖片,這時候 imageIndex[i]就是被打亂的下標,有可能是這樣的順序:{2,6,5,4,1,7,0,3,8},也有可能是這樣的順序{1,3,0,5,2,7,4,6,8}等等,不管怎么樣, imageIndex[8]一直是8,上面解釋過。代碼如下:

// ib00是綁定的第一塊圖片按鈕,設置圖片資源,// imageIndex[i]就是被打亂的下標,然后image[x]就表示對應下標為x的圖片的idib00.setImageResource(image[imageIndex[0]]);ib01.setImageResource(image[imageIndex[1]]);ib02.setImageResource(image[imageIndex[2]]);ib10.setImageResource(image[imageIndex[3]]);ib11.setImageResource(image[imageIndex[4]]);ib12.setImageResource(image[imageIndex[5]]);ib20.setImageResource(image[imageIndex[6]]);ib21.setImageResource(image[imageIndex[7]]);ib22.setImageResource(image[imageIndex[8]]);

綜上,disruptRandom()的整體邏輯代碼如下:

// 隨機打亂數組當中元素,以不規則的形式進行圖片顯示 private void disruptRandom() {// 給下標數組每個元素賦值,下標是i,值就為ifor (int i = 0; i < imageIndex.length; i++) { imageIndex[i] = i;}//規定20次,隨機選擇兩個角標對應的值進行交換int rand1,rand2;for (int j = 0; j < 20; j++) {// 隨機生成第一個角標// Math.random()產生的隨機數為0~1之間的小數 此處說的0~1是包含左不包含右,即包含0不包含1// Math.random()的值域為[0,1),然后*8就是[0,8),再int取整最終值域為{0,1,2,3,4,5,,6,7} rand1 = (int)(Math.random()*(imageIndex.length-1));// 第二次隨機生成的角標,不能和第一次隨機生成的角標相同,如果相同,就不方便交換了 do {rand2 = (int)(Math.random()*(imageIndex.length-1));// 判斷第一次和第二次生成的角標是否相同,不同則break立刻跳出循環,執行swap交換if (rand1!=rand2) { break;}// 若第二次生成的與第一次相同,則重新進入do-while循環生成rand2 }while (true);// 交換兩個角標上對應的值 swap(rand1,rand2);}//隨機排列到指定的控件上//ib00是綁定的第一塊圖片按鈕,設置圖片資源,imageIndex[i]就是被打亂的圖片數組下標,然后image[x]就表示對應下標為x的圖片的idib00.setImageResource(image[imageIndex[0]]);ib01.setImageResource(image[imageIndex[1]]);ib02.setImageResource(image[imageIndex[2]]);ib10.setImageResource(image[imageIndex[3]]);ib11.setImageResource(image[imageIndex[4]]);ib12.setImageResource(image[imageIndex[5]]);ib20.setImageResource(image[imageIndex[6]]);ib21.setImageResource(image[imageIndex[7]]);ib22.setImageResource(image[imageIndex[8]]); }

實現效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

4、拼圖游戲碎片位置切換

我們完成亂序后,這時候拼圖碎片還不能移動,所以我們要設置點擊事件,來移動拼圖。

拼圖移動的規則也要注意一下:只有和空白區域在同一行或者同一列相鄰的拼圖才能移動,只要知道了這個邏輯,實現起來就不難了。

我們來編寫九個圖片按鈕的onClick()方法

這里因為九個id不同的imagebutton點擊事件的邏輯相同,所以我們使用switch 語句來編寫,根據它們的id來執行移動,按照從左到右、從上到下的順序進行了case設置。移動我們定義了move()函數,將它單獨封裝成了一個方法,下面就會講到。點擊事件的代碼如下:

public void onClick(View view) {int id = view.getId();//九個按鈕執行的點擊事件的邏輯應該是相同的,如果有空格在周圍,可以改變圖片顯示的位置,否則點擊事件不響應switch (id) { case R.id.pt_ib_00x00:move(R.id.pt_ib_00x00,0);break; case R.id.pt_ib_00x01:move(R.id.pt_ib_00x01,1);break; case R.id.pt_ib_00x02:move(R.id.pt_ib_00x02,2);break; case R.id.pt_ib_01x00:move(R.id.pt_ib_01x00,3);break; case R.id.pt_ib_01x01:move(R.id.pt_ib_01x01,4);break; case R.id.pt_ib_01x02:move(R.id.pt_ib_01x02,5);break; case R.id.pt_ib_02x00:move(R.id.pt_ib_02x00,6);break; case R.id.pt_ib_02x01:move(R.id.pt_ib_02x01,7);break; case R.id.pt_ib_02x02:move(R.id.pt_ib_02x02,8);break;} }

我們來編寫九個圖片按鈕的move()方法

先定義變量,imageX是每行的圖片個數,imageY是每列的圖片個數,imgCount是圖片的總數目,也就是9個。blankSwap是空白區域的位置,就是8,這里的位置我們還是按照從左到右、從上到下的順序排列的,第一張圖片的位置是0,對照九宮格應該理解了吧。

blankImgid就是空白區域的按鈕id,我們這里直接固定了R.id.pt_ib_02x02,就是第九個圖片按鈕,它一直是空白區域!

// 每行的圖片個數 private int imageX = 3;// 每列的圖片個數 private int imageY = 3;// 圖片的總數目 private int imgCount = imageX*imageY;// 空白區域的位置 private int blankSwap = imgCount-1;// 初始化空白區域的按鈕id private int blankImgid = R.id.pt_ib_02x02;

定義完要用到的變量,我們來寫move方法,這里我每句都寫上了注釋,這里就不再贅述了。強調幾點:

1.可以移動的條件有兩個:

在同一行,列數相減,絕對值為1,可移動 在同一列,行數相減,絕對值為1,可以移動

2.兩個參數: imagebuttonId是被選中的圖片的id,site是該圖片在9宮格的位置(0-8)

3.將移動后的圖片按鈕設為不可見的,即顯示為空白區域

4.移動之前是不可見的,移動之后將圖標按鈕設置為可見

5.進行移動后將改變角標的過程記錄到存儲圖片位置的數組當中

/*表示移動指定位置的按鈕的函數,將圖片和空白區域進行交換*/ //imagebuttonId是被選中的圖片的id,site是該圖片在9宮格的位置(0-8) private void move(int imagebuttonId, int site) {//判斷選中的圖片在第幾行,imageX為3,所以進行取整運算int sitex = site / imageX;//判斷選中的圖片在第幾列,imageY為3,所以進行取模運算int sitey = site % imageY;//獲取空白區域的坐標,blankx為行坐標,blanky為列坐標int blankx = blankSwap / imageX;int blanky = blankSwap % imageY;//可以移動的條件有兩個//1.在同一行,列數相減,絕對值為1,可移動 2.在同一列,行數相減,絕對值為1,可以移動int x = Math.abs(sitex-blankx);int y = Math.abs(sitey-blanky);if ((x==0&&y==1)||(y==0&&x==1)){// 通過id,查找到這個可以移動的按鈕 ImageButton clickButton = findViewById(imagebuttonId);// 將這個選中的圖片設為不可見的,即顯示為空白區域 clickButton.setVisibility(View.INVISIBLE);// 查找到空白區域的按鈕 ImageButton blankButton = findViewById(blankImgid);// 將空白區域的按鈕設置為圖片,image[imageIndex[site]就是剛剛選中的圖片,因為這在上面disruptRandom()設置過 blankButton.setImageResource(image[imageIndex[site]]);// 移動之前是不可見的,移動之后將控件設置為可見 blankButton.setVisibility(View.VISIBLE);// 將改變角標的過程記錄到存儲圖片位置的數組當中 swap(site,blankSwap);// 新的空白區域位置更新等于傳入的點擊按鈕的位置 blankSwap = site;// 新的空白圖片id更新等于傳入的點擊按鈕的id blankImgid = imagebuttonId;} }

運行效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

5、拼圖游戲成功的條件

上面我們已經實現了拼圖碎片進行移動的效果,但是并沒有拼圖游戲成功的效果和提示,所以,我們要在剛剛的move方法的最后加上一個判斷的方法judgeGameOver();顧名思義:判斷游戲結束。

我們來實現一下判斷游戲結束的邏輯

在方法里面先定義一個loop標志位,然后要遍歷下標數組,判斷是否它的imageIndex[i]==i,就是說所有拼圖的下標全部對應正確的位置。比如:第1張圖片的下標是0,imageIndex[0]的值也是0,顯示第一張圖片。所有圖片都滿足,也就是說此時拼圖成功。如果一個不滿足,則未成功,所有loop置為false,繼續判斷。

boolean loop = true; //定義標志位loop for (int i = 0; i < imageIndex.length; i++) { if (imageIndex[i]!=i) {loop = false;break; } }

如果拼圖成功了,則handler.removeMessages(1)進行停止計時,而且設置ib00.setClickable(false)禁止玩家繼續移動按鈕,還有就是第九塊空白區域顯示出圖片,即下標為8的第九張拼圖。

if (loop) {// 拼圖成功了// 停止計時 handler.removeMessages(1);// 拼圖成功后,禁止玩家繼續移動按鈕 ib00.setClickable(false); ib01.setClickable(false); ib02.setClickable(false); ib10.setClickable(false); ib11.setClickable(false); ib12.setClickable(false); ib20.setClickable(false); ib21.setClickable(false); ib22.setClickable(false);// 拼圖成功后,第九塊空白顯示出圖片,即下標為8的第九張圖片 ib22.setImageResource(image[8]); ib22.setVisibility(View.VISIBLE);

我們再來實現一下游戲結束時的對話框

對話框要用到AlertDialog.Builder對象,它的使用就是固定套路,我來補充知識點:

第一步:創建AlertDialog.Builder對象 第二步:設置對話框的內容:setMessage()方法來指定顯示的內容 第三步:調用setPositive/Negative/NeutralButton()設置:確定,取消,中立按鈕 第四歩:調用create()方法創建這個對象 第五歩:調用show()方法來顯示我們的AlertDialog對話框

非常簡單,按照上面的流程,我們來設置下對話框:

// 彈出提示用戶成功的對話框,并且設置確實的按鈕// 第一步:創建AlertDialog.Builder對象 AlertDialog.Builder builder = new AlertDialog.Builder(this);// 調用setIcon()設置圖標,setTitle()或setCustomTitle()設置標題// 第二步:設置對話框的內容:setMessage()方法來指定顯示的內容 builder.setMessage('恭喜,拼圖成功!您用的時間為'+time+'秒')// 第三步:調用setPositive/Negative/NeutralButton()設置:確定,取消,中立按鈕 .setPositiveButton('確認',null);// 第四歩:調用create()方法創建這個對象 AlertDialog dialog = builder.create();// 第五歩:調用show()方法來顯示我們的AlertDialog對話框 dialog.show();

實現效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

6、拼圖游戲重新開始

我們在上面實現了拼圖游戲成功的條件和提示了,現在到了最后一步——如何讓游戲重新開始?

我們來看下拼圖成功后,點擊重新開始,目前只能重新計時,拼圖并沒有打亂,而且第九塊還沒有隱藏,所以,接下來我們的思路很明確,在重新開始的restart方法中編寫打亂和隱藏圖片的邏輯。

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

我們來實現重新開始游戲時的按鈕狀態還原

首先,這些按鈕已經被設置成不可點擊了,所以我們先要將它們設置為可以點擊,就是設置ib00.setClickable(true),因為這部分代碼都是一樣的,所以我們將它單獨封裝成一個restore方法。

另外,還要還原被點擊的圖片按鈕變成初始化的模樣, ImageButton clickBtn = findViewById(blankImgid)其實就是綁定最后一次被隱藏的那塊拼圖,然后clickBtn.setVisibility(View.VISIBLE)將它顯示出來。ImageButton blankBtn = findViewById(R.id.pt_ib_02x02)就是綁定的第九塊拼圖,blankBtn.setVisibility(View.INVISIBLE)設置為不可見。最后blankImgid = R.id.pt_ib_02x02來初始化空白區域的按鈕id。

restore()的代碼如下:

// 狀態還原函數,我們把它封裝起來 private void restore() {// 拼圖游戲重新開始,允許移動碎片按鈕ib00.setClickable(true);ib01.setClickable(true);ib02.setClickable(true);ib10.setClickable(true);ib11.setClickable(true);ib12.setClickable(true);ib20.setClickable(true);ib21.setClickable(true);ib22.setClickable(true);//還原被點擊的圖片按鈕變成初始化的模樣ImageButton clickBtn = findViewById(blankImgid);clickBtn.setVisibility(View.VISIBLE);//默認隱藏第九張圖片ImageButton blankBtn = findViewById(R.id.pt_ib_02x02);blankBtn.setVisibility(View.INVISIBLE);//初始化空白區域的按鈕idblankImgid = R.id.pt_ib_02x02;blankSwap = imgCount - 1; }

最后,我們在restart()中實現重新開始的邏輯

將狀態還原 將拼圖重新打亂 停止handler的消息發送 將時間重新歸0,并且重新開始計時 每隔1s發送參數what為1的消息msg

/* 重新開始按鈕的點擊事件*/ public void restart(View view) {//將狀態還原 restore();// 將拼圖重新打亂disruptRandom();// 停止handler的消息發送handler.removeMessages(1);// 將時間重新歸0,并且重新開始計時time = 0;timeTv.setText('時間 : '+time+' 秒');// 每隔1s發送參數what為1的消息msghandler.sendEmptyMessageDelayed(1,1000); }

重新開始游戲后的效果:

Android Studio做超好玩的拼圖游戲 附送詳細注釋源碼

至此,拼圖游戲的所有功能已經實現完畢,我先休息下,手腕已經打酸了。如果你看到這里,我真的很欣慰,說明你是個很有耐心而且熱愛Android的學生,有熱情有耐心,再困難的東西都可以學會。

五、運行效果

Android Studio實現拼圖游戲

六、項目總結

這次實現的拼圖游戲,說它簡單,其實它實現起來也并不是那么簡單,還是會有很多比較難的邏輯點,需要思考才能寫出來;說它難,其實也不算難,比起來我前面發的那些項目【天氣預報】、【飲食搭配】來說邏輯實現還是比較簡單的,畢竟它只有一個MainActivity和一個layout。所以,說一個項目的難易得看你選的參照物了。

這篇文章一共25000多個字,820行,我寫這篇文章,不連上寫代碼時間,前后一共11個小時,前面構思和注釋了4個小時,然后具體寫了7個小時,中間只有喝水and上廁所。可以說我完全是按照開發這款拼圖游戲的邏輯順序來寫下這篇教程。就是我們平時怎么開發Android項目,這篇博客就是怎么寫的。

我之所以寫的這么詳細,也是因為現在網上缺少一個從頭到尾講實現過程的Android項目的教程,因為這實在太花時間了,我深有體會,極少有人一步一步地去把實現過程寫出來,但是我還是決定寫下這篇教程,為了讓更多的人喜歡上Android,讓更多的人對Android不再陌生,讓小白們不再望而卻步,讓小白們有個很好的實現案例,這是我的想法。

當然,我也是正在學習Android的選手之一,才疏學淺,知識淺薄,文章中難免會有紕漏和錯誤,還希望大佬們批評指正。

七、項目源碼

這次的拼圖游戲項目是一個非常好的Android實現案例,涉及到很多常用的控件和知識點,希望大家拿到源碼后,能對照著教程和注釋好好學習掌握。

源碼幾乎每條語句我都加上了注釋,這么良心的博主,點個三連支持下吧,源碼就送你啦,祝大家身體健康,學習愉快~

鏈接:拼圖游戲源碼

面向陽光時,陰影在你背后。背向陽光時,陰影在你眼前。世界從未改變,改變的只是我們面對世界的方向!加油!你值得更好!

到此這篇關于帶你用Android Studio做超好玩的拼圖游戲,0基礎小白也能包你學會,附送帶有超詳細注釋源碼的文章就介紹到這了,更多相關Android拼圖游戲內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
主站蜘蛛池模板: 国产精品久久精品视 | 99亚洲 | 欧美区一区二区三 | 国产高清色播视频免费看 | 国产农村乱色xxxx | 羞羞影院免费观看网址在线 | 国产精品区网红主播在线观看 | 成人社区网站 | 在线不卡一区二区三区日韩 | 美女在线国产 | 一区二区三区四区在线不卡高清 | 黄色成人在线观看 | 九草在线视频 | 午夜国产大片免费观看 | 一级毛片在线完整免费观看 | 国产精品黄页网站在线播放免费 | 欧美黄色一级大片 | 俺也操| 亚洲欧美视频一区 | 国产精品国产三级国产专不∫ | 国产成人麻豆tv在线观看 | 亚洲爱v| 麻豆国产在线观看一区二区 | 日韩黄色片在线观看 | 国产成人a毛片在线 | 激情小视频在线播放免费 | 9久9久女女免费精品视频在线观看 | 青青青国产依人免费视频 | 国产成人精品日本 | 成年人黄色小视频 | 99久久伊人一区二区yy5099 | 一级毛片黄色片 | 一区二区视频在线观看免费的 | 久热re这里只有精品视频 | 亚洲无成人网77777 | 免费二级c片在线观看a | 偷窥自拍15p | 日本一视频一区视频二区 | 激情在线日韩视频免费 | 日本中文字幕精品理论在线 | 国产成人精品午夜在线播放 |