有一段时间没写安卓的代码,慢慢的有点忘了,这个按照视频一步一步来的复原
主要步骤:
1.把一张大图分成多个方块图,GridLayout实现
2.设置某个方块为缺口(拼图是总有一个空白的方块)
3.点击交换缺口与相邻方块的数据
4.获取手势,手势交换缺口与相邻方块的数据
5.打乱顺序
6.判断结束
按钮背景,放在drawable文件夹下,命名bg_btn
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<!-- 定义当button 处于pressed 状态时的形态。-->
<shape>
<gradient android:startColor="#8600ff" />
<stroke android:width="2dp" android:color="#000000" />
<corners android:radius="5dp" />
<padding android:left="10dp" android:top="10dp"
android:bottom="10dp" android:right="10dp" />
</shape>
</item>
<item android:state_pressed="false">
<!-- 定义当button 处于pressed 状态时的形态。-->
<shape>
<gradient android:startColor="#aeaeae" android:endColor="#b0b0b0" />
<stroke android:width="2dp" android:color="#333333" />
<corners android:radius="5dp" />
<padding android:left="10dp" android:top="10dp"
android:bottom="10dp" android:right="10dp" />
</shape>
</item>
</selector>
View Code
布局文件activity_main.xml
<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=".MainActivity" >
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/gl_main_game"
android:columnCount="4"
android:rowCount="5"
android:fillViewport="true"
>
</GridLayout>
<Button
android:id="@+id/btn_start"
android:layout_width="120px"
android:layout_height="60px"
android:layout_marginRight="5px"
android:layout_marginLeft="5px"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20px"
android:background="@drawable/bg_btn"
android:text="Start" />
<Button
android:id="@+id/btn_back"
android:layout_width="120px"
android:layout_height="60px"
android:layout_toLeftOf="@+id/btn_start"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20px"
android:background="@drawable/bg_btn"
android:text="Back" />
<Button
android:id="@+id/btn_select"
android:layout_width="120px"
android:layout_height="60px"
android:layout_toRightOf="@+id/btn_start"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20px"
android:background="@drawable/bg_btn"
android:text="Select" />
</RelativeLayout>
View Code
主函数实现逻辑
package com.example.jigsaw;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.view.GestureDetector.OnGestureListener;//手势监听包,不提示导入??
public class MainActivity extends Activity {
/**当前移动动画是否正在执行*/
private boolean isAnimRun = false;
/** 利用二维数组创建若干小方块 **/
private ImageView[][] iv_game_arr = new ImageView[5][4];
/** 游戏主界面 **/
private GridLayout gl_main_game;
/** 当前空方块的实例保存 **/
private ImageView iv_null_ImageView;
/** 当前手势 */
private GestureDetector mDetector;
/**判断游戏是否开始,默认没开始*/
private boolean isGameStart = false;
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
return mDetector.onTouchEvent(event);// 把界面监听换成手势监听
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
mDetector.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDetector = new GestureDetector(MainActivity.this,
new OnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1,
float arg2, float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1,
float arg2, float arg3) {
int type = getDirByGes(arg0.getX(), arg0.getY(),
arg1.getX(), arg1.getY());// 判断手势返回int类型
// Toast.makeText(MainActivity.this, "" +
// type,Toast.LENGTH_SHORT).show();
changeByDir(type);// 移动换图
return false;
}
@Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
});
setContentView(R.layout.activity_main);
/** 初始化游戏的若干小方块 */
// 获取一张大图片
Bitmap bigBm = ((BitmapDrawable) getResources().getDrawable(
R.drawable.kenan1)).getBitmap();
int tuWandW = bigBm.getWidth() / (iv_game_arr.length);// 每个游戏块的宽和高
int tvWandH= this.getWindowManager().getDefaultDisplay().getWidth()/ (iv_game_arr.length-1);//小方块的宽度应为屏幕的平均值
for (int i = 0; i < iv_game_arr.length; i++) {
for (int j = 0; j < iv_game_arr[i].length; j++) {
Bitmap bm = Bitmap.createBitmap(bigBm, j * tuWandW,
i * tuWandW, tuWandW, tuWandW);// 根据行和列切成若干个游戏小图片
iv_game_arr[i][j] = new ImageView(this);
iv_game_arr[i][j].setImageBitmap(bm);// 设置每一个小方块的图片
iv_game_arr[i][j].setLayoutParams(new RelativeLayout.LayoutParams(tvWandH, tvWandH));//设置宽高
iv_game_arr[i][j].setPadding(2, 2, 2, 2);// 设置方块的间距
iv_game_arr[i][j].setTag(new GameData(i, j, bm));// 绑定自定义数据
// 设置点击监听,判断位置关系
iv_game_arr[i][j].setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
boolean flag = isHasByNullImageView((ImageView) v);
// Toast.makeText(MainActivity.this, "位置关系是否存在:"+flag,
// Toast.LENGTH_SHORT).show();
if (flag) {
changeDataByImageView((ImageView) v);
}
}
});
}
}
// 初始化游戏界面,并添加若干小方块
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[i].length; j++) {
gl_main_game.addView(iv_game_arr[i][j]);
}
}
/** 设置第一个方块为空 */
setNullIamgeView(iv_game_arr[0][0]);
Button btnStart=(Button) findViewById(R.id.btn_start);//button点击之后打乱
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
/** 初始化随机打乱顺序方块 */
randomMove();
isGameStart = true;//开始状态
}
});
}
/**
* 根据手势的方向,获取空方块相应的相邻位置如果存在方块,那么进行数据交换
*
* @param type
* 1:上,2:下,3:左,4:右
*/
public void changeByDir(int type) {
changeByDir(type, true);
}
/**
* 根据手势的方向,获取空方块相应的相邻位置如果存在方块,那么进行数据交换
*
* @param type
* 1:上,2:下,3:左,4:右
* @param isAnim
* ture:有动画,false:无动画
*/
public void changeByDir(int type, boolean isAnim) {
// 获取当前空方块的位置
GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
// 根据方向,设置相应的相邻的位置坐标
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++) {
//为空的方块数据不判断
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;
}
}
}
//根据一个开关变量决定游戏是否结束,结束时给提
if (isGameOver) {
Toast.makeText(MainActivity.this, "游戏结束", Toast.LENGTH_SHORT).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() {
// 打乱的次数
for (int i = 0; i < 100; i++) {
// 根据手势开始交换,无动画
int type = (int) (Math.random() * 4) + 1;// 随机数得到[0,4)之间的数,加上一就是移动的顺序
changeByDir(type, false);
}
}
/**
* 利用动画结束之后,交换两个方块的数据
*
* @param mImageView
* 点击的方块
*/
public void changeDataByImageView(final ImageView mImageView) {
changeDataByImageView(mImageView, true);
}
/**
* 利用动画结束之后,交换两个方块的数据
*
* @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;
setNullIamgeView(mImageView);// 设置当前点击的为空模块
if (isGameStart) {//开始后每一次移动都要判断是否结束
isGameOver();// 成功时会弹一个toast
}
return;
}
// 创建一个动画,设置好方向,移动距离
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.getY() > iv_null_ImageView.getY()) {
// 往左移
translateAnimation = new TranslateAnimation(0.1f, 0.1f, 0.1f,
-mImageView.getWidth());
} else if (mImageView.getY() < iv_null_ImageView.getY()) {
// 往右移
translateAnimation = new TranslateAnimation(0.1f, 0.1f, 0.1f,
mImageView.getWidth());
}
// 设置动画的的时长
translateAnimation.setDuration(70);
// 设置动画结束之后时候是否停留
translateAnimation.setFillAfter(true);
// 设置动画结束之后要真正的把数据交换了
translateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
isAnimRun = true;
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animation arg0) {
// TODO Auto-generated method stub
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;
setNullIamgeView(mImageView);// 设置当前点击的为空模块
if (isGameStart) {//开始后每一次移动都要判断是否结束
isGameOver();// 成功时会弹一个toast
}
}
});
// 执行动画
mImageView.startAnimation(translateAnimation);
}
/**
* 设置某个方块为空
*
* @param mImageView
* 当前要设置为空的方块实例
*/
public void setNullIamgeView(ImageView mImageView) {
mImageView.setImageBitmap(null);
// mImageView.setBackgroundColor(10);//设置空的背景色
iv_null_ImageView = mImageView;
}
/**
* 判断当前点击的方块,是否与空方块的位置关系是否相邻
*
* @param mImageView
* 点击的方块实例
* @return true:相邻,false:不相邻
*/
public boolean isHasByNullImageView(ImageView mImageView) {
// 分别获取当前空方块的位置与点击方块的位置,通过x,y两边都差一的方式判断
GameData mNullGameData = (GameData) iv_null_ImageView.getTag();
GameData mGameData = (GameData) mImageView.getTag();
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 == mNullGameData.x) {// 当前点击的方块在空方块的右边
return true;
}
return false;
}
/**
* 每个游戏小方块上要绑定的数据
*/
class GameData {
/** 每个小方块的实际位置x */
public int x = 0;
/** 每个小方块的实际位置y */
public int y = 0;
/** 每个小方块的图片 */
public Bitmap bm;
/** 每个小方块的图片的位置x */
public int p_x = 0;
/** 每个小方块的图片的位置y */
public int p_y = 0;
public GameData(int x, int y, Bitmap bm) {
super();
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;
}
}
}
View Code
效果如下: