Android實現(xiàn)拼圖小游戲
本文實例為大家分享了Android實現(xiàn)拼圖小游戲的具體代碼,供大家參考,具體內容如下
目標效果:

1.activity_main.xml頁面:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.vivinia.puzzle.MainActivity"> <GridLayout android:id="@+id/gl_main_game" android:layout_width="match_parent" android:layout_height="match_parent" android:rowCount="3" android:columnCount="5"> </GridLayout> </RelativeLayout>
2.MainActivity.java頁面:
package com.example.vivinia.puzzle;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
/**
* 當前動畫是否正在執(zhí)行
*/
private boolean isAnimRun=false;
/**
*判斷游戲是否開始*/
private boolean isGameStart=false;
/**
*利用二維數(shù)組創(chuàng)建若干個游戲小方塊
*/
private ImageView[][] iv_game_arr = new ImageView[3][5];
/**
*游戲主界面
*/
private GridLayout gl_main_game;
/**
*當前空方塊的實例保存
*/
private ImageView iv_null_ImageView;
/**
*當前手勢
*/
private GestureDetector mDetector;
//非圖片位置可以進行手勢滑動
@Override
public boolean onTouchEvent(MotionEvent event) {
return mDetector.onTouchEvent(event); //手勢監(jiān)聽
}
//在圖片上可以進行手勢滑動
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDetector=new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
}
/**
*一瞬間執(zhí)行的方法
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float v, float v1) {
int type=getDirByGes(e1.getX(),e1.getY(),e2.getX(),e2.getY());
changeByDir(type);
return false;
}
});
setContentView(R.layout.activity_main);
//初始化游戲的若干個小方塊
Bitmap bigBm=((BitmapDrawable)getResources().getDrawable(R.drawable.puzzle_bg)).getBitmap();
int everyWidth=bigBm.getWidth()/5; //每個游戲小方塊的寬和高
for (int i = 0; i < iv_game_arr.length; i++) {
for (int j = 0; j < iv_game_arr[0].length; j++) {
Bitmap bm=Bitmap.createBitmap(bigBm,j*everyWidth,i*everyWidth,everyWidth,everyWidth);//根據(jù)行列來切成若干個游戲小圖片
iv_game_arr[i][j]=new ImageView(this);
iv_game_arr[i][j].setImageBitmap(bm); //設置每一個游戲小方塊圖案
iv_game_arr[i][j].setPadding(2,2,2,2);//設置方塊之間的間距
iv_game_arr[i][j].setTag(new GameData(i,j,bm)); //綁定自定義的數(shù)據(jù)
iv_game_arr[i][j].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean flag=isHasByNullImageView((ImageView)view);
if(flag){
changeDataByImageView((ImageView)view);
}
}
});
}
}
//初始化游戲主界面,并添加若干個小方塊
gl_main_game = (GridLayout) findViewById(R.id.gl_main_game);
for(int i=0;i<iv_game_arr.length;i++){
for(int j=0;j<iv_game_arr[0].length;j++){
gl_main_game.addView(iv_game_arr[i][j]);
}
}
/**
*設置最后一個方塊為空的
*/
setNullImageView(iv_game_arr[2][4]);
/**
*初始化隨機打亂順序
*/
randomMove();
isGameStart=true; //開始狀態(tài)
}
public void changeByDir(int type){
changeByDir(type,true);
}
/**
* 根據(jù)手勢的方向,獲取空方塊相應的相鄰位置如果存在方塊,那么進行數(shù)據(jù)交換
* @param type 1:上,2:下,3:左,4:右
* @param isAnim true:有動畫,false:無動畫
*/
public void changeByDir(int type,boolean isAnim){
/**
*獲取當前空方塊的位置
*/
GameData mNullGameData= (GameData) iv_null_ImageView.getTag();
/**
* 根據(jù)方向,設置相應的相鄰的位置的坐標
*/
int new_x=mNullGameData.x;
int new_y=mNullGameData.y;
if(type==1){ //要移動的方塊在當前空方塊的下邊
new_x++;
}else if(type==2){ //要移動的方塊在當前空方塊的下邊
new_x--;
}else if(type==3){ //要移動的方塊在當前空方塊的下邊
new_y++;
}
else if(type==4){ //要移動的方塊在當前空方塊的下邊
new_y--;
}
/**
*判斷這個新坐標,是否存在
*/
if(new_x>=0&&new_x<iv_game_arr.length&&new_y>=0&&new_y<iv_game_arr[0].length){
if(isAnim) {
/**
*存在的話,開始移動
*/
changeDataByImageView(iv_game_arr[new_x][new_y]);
}else{
changeDataByImageView(iv_game_arr[new_x][new_y],isAnim);
}
}else{
//什么也不做
}
}
/**
*判斷游戲結束的方法
*/
public void isGameOver(){
boolean isGameOver=true;
//要便利每個游戲小方塊
for(int i=0;i<iv_game_arr.length;i++){
for(int j=0;j<iv_game_arr[0].length;j++){
//為空的方塊數(shù)據(jù)不判斷跳過
if(iv_game_arr[i][j]==iv_null_ImageView){
continue;
}
GameData mGameData= (GameData) iv_game_arr[i][j].getTag();
if(!mGameData.isTrue()){
isGameOver=false;
break;
}
}
}
//根據(jù)一個開關變量決定游戲是否結束,結束時給提示
if(isGameOver){
Toast.makeText(this,"游戲結束",Toast.LENGTH_LONG).show();
}
}
/**
* 手勢判斷,是向左還是向右
* @param start_x 手勢的起始點x
* @param start_y 手勢的起始點y
* @param end_x 手勢的終止點x
* @param end_y 手勢的起始點y
* @return 1:上,2:下,3:左,4:右
*/
public int getDirByGes(float start_x,float start_y,float end_x,float end_y){
boolean isLeftOrRight=(Math.abs(start_x-end_x)>Math.abs(start_y-end_y))?true:false; //是否左右
if(isLeftOrRight){ //左右
boolean isLeft=start_x-end_x>0?true:false;
if(isLeft){
return 3;
}else{
return 4;
}
}else{ //上下
boolean isUp=start_y-end_y>0?true:false;
if(isUp){
return 1;
}else{
return 2;
}
}
}
/**
* 隨機打亂順序
*/
public void randomMove(){
//打亂的次數(shù)
for(int i=0;i<10;i++){
//根據(jù)手勢開始交換,無動畫
int type=(int)(Math.random()*4)+1;
changeByDir(type,false);
}
}
public void changeDataByImageView(final ImageView mImageView) {
changeDataByImageView(mImageView,true);
}
/**
* 利用動畫結束之后,交換兩個方塊的數(shù)據(jù)
* @param mImageView 點擊的方塊
* @param isAnim true:有動畫,false:無動畫
*/
public void changeDataByImageView(final ImageView mImageView,boolean isAnim){
if(isAnimRun){ //如果動畫已經開始,則不做交換操作
return;
}
if(!isAnim){ //如果沒有動畫
GameData mGameData= (GameData) mImageView.getTag();
iv_null_ImageView.setImageBitmap(mGameData.bm);
GameData mNullGameData= (GameData) iv_null_ImageView.getTag();
mNullGameData.bm=mGameData.bm;
mNullGameData.p_x=mGameData.p_x;
mNullGameData.p_y=mGameData.p_y;
setNullImageView(mImageView); //設置當前點擊的是空方塊
if(isGameStart) {
isGameOver(); //成功時談一個toast
}
return;
}
/**
*創(chuàng)建一個動畫,設置好方向,移動的距離
*/
TranslateAnimation translateAnimation = null;
if(mImageView.getX()>iv_null_ImageView.getX()){ //當前點擊的方塊在空方塊下邊
//往上移動
translateAnimation=new TranslateAnimation(0.1f,-mImageView.getWidth(),0.1f,0.1f);
}else if(mImageView.getX()<iv_null_ImageView.getX()){ //當前點擊的方塊在空方塊下邊
//往下移動
translateAnimation=new TranslateAnimation(0.1f,mImageView.getWidth(),0.1f,0.1f);
}
else if(mImageView.getX()>iv_null_ImageView.getY()){ //當前點擊的方塊在空方塊下邊
//往左移動
translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,-mImageView.getWidth());
}
else if(mImageView.getX()<iv_null_ImageView.getY()){ //當前點擊的方塊在空方塊下邊
//往右移動
translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,mImageView.getWidth());
}
/**
* 設置動畫的時長
*/
translateAnimation.setDuration(70);
/**
* 設置動畫結束之后是否停留
*/
translateAnimation.setFillAfter(true);
/**
* 設置動畫結束之后真正的交換數(shù)據(jù)
*/
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
isAnimRun=true; //動畫開始
}
@Override
public void onAnimationEnd(Animation animation) {
isAnimRun=false; //動畫結束
/**
*結束之后,清除動畫
*/
mImageView.clearAnimation();
GameData mGameData= (GameData) mImageView.getTag();
iv_null_ImageView.setImageBitmap(mGameData.bm);
GameData mNullGameData= (GameData) iv_null_ImageView.getTag();
mNullGameData.bm=mGameData.bm;
mNullGameData.p_x=mGameData.p_x;
mNullGameData.p_y=mGameData.p_y;
setNullImageView(mImageView); //設置當前點擊的是空方塊
if(isGameStart) {
isGameOver(); //成功時談一個toast
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
/**
* 執(zhí)行動畫
*/
mImageView.startAnimation(translateAnimation);
}
/**
* 設置某個方塊為空方塊
* @param mImageView 當前要設置為空的方塊的實例
*/
public void setNullImageView(ImageView mImageView){
mImageView.setImageBitmap(null); //設置為空
iv_null_ImageView=mImageView;
}
/**
* 判斷當前點擊的方塊,是否與空方塊的位置關系是相鄰關系
* @param mImageView 所點擊的方塊
* @return true:相鄰;false:不相鄰
*/
public boolean isHasByNullImageView(ImageView mImageView){
/**
*分別獲取當前空方塊的位置與點擊方塊的位置,通過x,y兩邊都差1的方式判斷
*/
GameData mNullGameData= (GameData) iv_null_ImageView.getTag(); //空方塊身上的數(shù)據(jù)
GameData mGameData= (GameData)mImageView.getTag(); //點擊方塊身上的數(shù)據(jù)
if(mNullGameData.y==mGameData.y&&mGameData.x+1==mNullGameData.x){ //當前點擊的方塊在空方塊的上邊
return true;
}else if(mNullGameData.y==mGameData.y&&mGameData.x-1==mNullGameData.x){ //當前點擊的方塊在空方塊的下邊
return true;
}else if(mNullGameData.y==mGameData.y+1&&mGameData.x==mNullGameData.x){ //當前點擊的方塊在空方塊的左邊
return true;
}else if(mNullGameData.y==mGameData.y-1&&mGameData.x+1==mNullGameData.x){ //當前點擊的方塊在空方塊的右邊
return true;
}
return false;
}
/**
* 每個游戲小方塊上要綁定的數(shù)據(jù)
*/
class GameData{
/**
*每個小方塊的實際位置x
*/
public int x=0;
/**
*每個小方塊的實際位置x
*/
public int y=0;
/**
*每個小方塊的圖片
*/
public Bitmap bm;
/**
*每個小方塊的圖片的位置
*/
public int p_x=0;
/**
*每個小方塊的圖片的位置
*/
public int p_y=0;
public GameData(int x, int y, Bitmap bm) {
this.x = x;
this.y = y;
this.bm = bm;
this.p_x = x;
this.p_y = y;
}
/**
* 每個小方塊的位置是否正確
* @return true:正確,false:不正確
*/
public boolean isTrue() {
if(x==p_x&&y==p_y) {
return true;
}
return false;
}
}
}
3.設置去掉標題欄樣式
styles.xml頁面:
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="MyAppTheme" parent="AppTheme"> <item name="windowNoTitle">true</item> <item name="windowActionBar">false</item> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item> </style> </resources>
4.清單文件中使用該樣式
AndroidManifest.xml頁面:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.vivinia.puzzle"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/MyAppTheme"> <activity android:name=".MainActivity" android:screenOrientation="landscape"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
源碼下載:點擊打開鏈接
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
android使用viewpager計算偏移量實現(xiàn)選項卡功能
這篇文章主要為大家詳細介紹了android使用viewpager計算偏移量實現(xiàn)選項卡功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12
Kotlin創(chuàng)建一個好用的協(xié)程作用域
這篇文章主要介紹了Kotlin創(chuàng)建一個好用的協(xié)程作用域,kotlin中使用協(xié)程,是一定要跟協(xié)程作用域一起配合使用的,否則可能協(xié)程的生命周期無法被準確控制,造成內存泄漏或其他問題2022-07-07
解決Android Studio 格式化快捷鍵和QQ 鎖鍵盤快捷鍵沖突問題
每次打開qq使用android studio格式化的快捷鍵Ctrl + Alt +L時,總是出現(xiàn)qq鎖鍵盤提示,怎么回事呢?下面小編給大家?guī)砹薬ndroid studio格式化的快捷鍵和qq快捷鍵之間的沖突的處理方法,需要的朋友參考下吧2017-12-12
Android開發(fā)之微信底部菜單欄實現(xiàn)的幾種方法匯總
這篇文章主要介紹了Android開發(fā)之微信底部菜單欄實現(xiàn)的幾種方法,下面小編把每種方法通過實例逐一給大家介紹,需要的朋友可以參考下2016-09-09
Android Tween動畫之RotateAnimation實現(xiàn)圖片不停旋轉效果實例介紹
Android中如何使用rotate實現(xiàn)圖片不停旋轉的效果,下面與大家共同分析下Tween動畫的rotate實現(xiàn)旋轉效果,感興趣的朋友可以參考下哈2013-05-05
Android 實現(xiàn)可任意拖動的懸浮窗功能(類似懸浮球)
這篇文章主要介紹了Android 可任意拖動的懸浮窗(類似懸浮球),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05

