Android應用開發入門篇-拼圖遊戲

前一段時間為瞭學習android應用開發,嘗試寫瞭個簡單的拼圖應用,在此記錄下實現流程的核心部分,同時也希望給其他開發者入門參考帶來幫助。

1. 基本的界面設計

首先應該設計出各個界面(Activity)的樣式以及界面間跳轉需要通過Intent傳遞哪些數據。本例包括4個Activity:

a. MainActivity主界面,隻包含1個TextView和3個ButtonView,每個按鈕點擊應改變難度的值,這個值應該同過Intent繼續傳遞下去的;

b. SourceActivity圖片源選取,這個界面應成Dialog對話框形式展現 ,要在AndroidManifest.xml文件中聲明,然後控件采用ListView;vcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ==”brush:java;”>

c. GameActivity遊戲界面,核心就是上面的1個ImageView,此外有1個ButtonView和2個TextView;

d. EndActivity最後一個結束界面沒有什麼特殊的,主要是為瞭提醒遊戲結束,同樣是一個Dialog風格的Activity,與b同。

有瞭以上4個界面這個簡單的遊戲框架就有瞭,接下來重點就是實現b和c界面中的功能瞭。

2. 拍照或從相冊選取圖片

這個首先要在AndroidManifest.xml文件中設置下允許SD卡讀寫

    
    
    
        
    
    

然後,相機拍照並保存的代碼如下,主要圖片保存路徑的設置(SD卡路徑+圖片文件夾路徑)

				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				//獲取SD卡對應的存儲目錄
	            File sdCardDir = Environment.getExternalStorageDirectory();
	            //將拍照時間作為照片文件名並保存
	            Date date = new Date();
	            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");//獲取當前時間,進一步轉化為字符串
	            String path = null;
				try {
					path = sdCardDir.getCanonicalPath() + "/DCIM/Camera/";
				} catch (IOException e) {
					e.printStackTrace();
				}
	            String fileName = "IMG_" + format.format(date) + ".jpg";       
				Uri imageUri = Uri.fromFile(new File(path, fileName));  
				filePath = path + fileName; 				
				//指定照片保存路徑(SD卡)
				intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
				startActivityForResult(intent, 0);

從相冊選取圖片隻需要如下幾行

				Intent intent = new Intent(Intent.ACTION_PICK);
				intent.setType("image/*");
				startActivityForResult(intent, 1);

以上兩種選擇圖片都調用瞭startActivityForResult方法,主要requestCode參數需要不同,對應的響應方法及實現代碼如下:

    @Override  
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        super.onActivityResult(requestCode, resultCode, data);  
            
        if (requestCode == 0 && resultCode == RESULT_OK) {  
			//pass
        }  
        else if(requestCode == 1 && resultCode == RESULT_OK){ 
        	//The 3 lines below is useful!
            Cursor cursor = this.getContentResolver().query(data.getData(), null, null, null, null);  
            cursor.moveToFirst();  
            filePath = cursor.getString(cursor.getColumnIndex("_data"));         
        }
        
        Intent intent = new Intent();
        intent.setClass(SourceActivity.this, GameActivity.class);
        intent.putExtra("imgPath", filePath);//將獲得的圖片路徑傳遞到GameActivity即可
        intent.putExtra("level", level);
        startActivity(intent);	  
        finish();
    }  

3. 將圖片隨機切割

上一步傳遞圖片路徑到GameActivity,但是我們讀取圖像不可能把幾MB的圖像放在ImageView裡,實際采用的是Bitmap讀入圖像(此時圖像已被縮小),用變量記錄縮小的scale。然後將這個Bitmap顯示到ImageView上是沒有問題的,通過設置匹配方式為centerCrop,圖像會很舒服的顯示出來。難題在於,點擊開始後需要隨機切割圖像並顯示。由於Bitmap雖然縮小瞭原圖像,但是仍保持原圖的長寬比,而這個比例和ImageView的比例一般是不一樣的,所以如果直接在原始Bitmap上切割的話,顯示在ImageView裡的圖像一定不是規整的3*3或5*5圖塊。

解決辦法,需要在原始Bitmap上先進行按ImageView比例的centerCrop裁剪, 方法如下

	private Bitmap centerCrop(Bitmap src, int W, int H){
		int w = src.getWidth();
		int h = src.getHeight();
		float ratio = (float)W/H;
		Bitmap dst = null;
		if(((float)w/h) > ratio){//crop width
			dst = Bitmap.createBitmap(src_bitmap, (int)((w-ratio*h)/2), 0, (int)(ratio*h), h);
		}else{//crop height
			dst = Bitmap.createBitmap(src_bitmap, 0, (int)((h-w/ratio)/2), w, (int)(w/ratio));
		}
		return dst;
	}

然後顯示的就是規整的3*3(初級)或5*5(中級)模式瞭,這裡省略瞭隨機切割圖像塊的方法,主要就是通過Random類的對象生成隨機數(但是不能重復)。此外,用到瞭一個Bitmap的數組來保存每個圖塊,一個int數組保存每個位置的圖塊索引。

4. 點擊交換圖塊位置

給ImageView綁定一個OnTouchListener接口的實現,點擊圖像時觸發。

	class ImageListener implements OnTouchListener{
		@Override
		public boolean onTouch(View arg0, MotionEvent arg1) {
			float x = arg1.getX();//get clicked x position
			float y = arg1.getY();//get clicked y position
			int tmp_col = (int) (x / (width/col));
			int tmp_row = (int) (y / (height/row));
			int new_chosen_num = tmp_row * col + tmp_col;
			if((chosen_num != -1) && (new_chosen_num != chosen_num)){//do swap
				swapBlock(chosen_num, new_chosen_num);
				txt_count.setText(step+"");
				chosen_num = -1;
				if(mis_count == 0){//Game Win!
					Intent intent = new Intent();
					intent.setClass(GameActivity.this, EndActivity.class);
					startActivity(intent);					
				}
			}else{//set one chosen
				chosen_num = new_chosen_num;
			}
			return false;
		}		
	}

最後交換圖像塊後ImageView上的顯示問題用到瞭Canvas,相當於把Bitmap作為一個畫佈,在上面畫出交換結果,然後將新Bitmap顯示到ImageView上。

		Canvas to_draw = new Canvas(new_bitmap);
		for(int i = 0; i < row; i++)
			for(int j = 0; j < col; j++)
				to_draw.drawBitmap(pic_arr[i * row + j], j*(tmp_width/col), i*(tmp_height/row), null);
		to_draw.save(Canvas.ALL_SAVE_FLAG);
		to_draw.restore();
		img.setImageBitmap(new_bitmap);
		img.setOnTouchListener(new ImageListener());

以上內容總結的很潦草,可能更方便自己日後查看,裡面的一些代碼可能缺少連貫性。隻希望某些地方的處理方法能給入門的朋友一些借鑒,如果有不清楚想仔細瞭解的朋友請留言。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *