拼图虽是比较小的一个游戏,但涉及到的逻辑和代码也没那么简单,这里参考慕课网上的教程,采用一个二维数组来存储拼图的小方格,并将拼图的数据GameData(包括x,y坐标和正确的摆放位置)和视图(Bitmap)分离,并编写相应的游戏逻辑控制方法(控制层controller),很好地体现了MVC的思想。
视频网站:http://www.imooc.com/learn/683
效果图:

源代码:

package com.pintu;import android.graphics.Bitmap;import android.graphics.BitmapFactory;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 {    //利用二位数组创建若干个游戏小方块    private ImageView[][] iv_game_arr = new ImageView[3][5];    //游戏主界面    private GridLayout gl_main_game ;    //当前手势    private GestureDetector mDetector ;    private boolean isGameStart;    //保存当前空方块的实例    private ImageView iv_null ;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {            @Override            public boolean onDown(MotionEvent e) {                return false;            }            @Override            public void onShowPress(MotionEvent e) {            }            @Override            public boolean onSingleTapUp(MotionEvent e) {                return false;            }            @Override            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {                return false;            }            @Override            public void onLongPress(MotionEvent e) {            }            @Override            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {                int type = getDirByGes(e1.getX() , e1.getY() , e2.getX() , e2.getY());                changeByDir(type , true );                return false;            }        });        setContentView(R.layout.activity_main);        //初始化游戏的若干个小方块        //获取一张大图        Bitmap bigBm = BitmapFactory.decodeResource(getResources(),R.drawable.pingtu);        //每个游戏小方块的宽和高        int width = 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 * width , i * width , width , width) ;                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 ));                iv_game_arr[i][j].setOnClickListener(new View.OnClickListener() {                    @Override                    public void onClick(View v) {                        boolean flag = isNearNullImageView((ImageView) v);                        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[0].length ; j++ ){                gl_main_game.addView(iv_game_arr[i][j]);            }        }        //设置最后一个方块为空        setNullImageView(iv_game_arr[2][4]);        //初始化随机打乱顺序的方块        randomMove();        isGameStart = true ;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        return mDetector.onTouchEvent(event);    }    public void changeByDir( int type ){        changeByDir(type , true);    }    /**     * 根据手势的方向,获取空方块相应的相邻位置,如果存在方块,那么进行数据交换     * @param type 1 : 上 , 2 : 下 , 3 : 左 , 4 : 右     * @param isAnim 是否有动画     */    public void changeByDir( int type , boolean isAnim ){        //获取当前空方块的位置        GameData mNullGameData = (GameData) iv_null.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 {            //什么也不做        }    }    /**     * 手势判断,向左滑还是向右滑     * @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 < 15; i ++ ){            //根据手势开始交换,无动画            int type = (int)(Math.random() * 4 ) + 1 ;            changeByDir(type,false);        }    }    public void changeDataByImageView(final ImageView imageView ){        changeDataByImageView(imageView,true);    }    /**     * 动画结束之后,交换两个方块的数据     */    public void changeDataByImageView(final ImageView imageView , boolean isAnim){        if( !isAnim ){            GameData mGameData = (GameData) imageView.getTag();            iv_null.setImageBitmap(mGameData.bm);            GameData mNullGameData = (GameData) iv_null.getTag();            mNullGameData.bm = mGameData.bm ;            mNullGameData.p_x = mGameData.p_x ;            mNullGameData.p_y = mGameData.p_y ;            //设置当前点击的方块为空方块            setNullImageView(imageView);            if( isGameStart){                isGameOver();            }            return;        }        //创建一个动画,设置好方向,移动距离        TranslateAnimation translateAnimation = null  ;        if( imageView.getX() > iv_null.getX() ){//当前点击的方块在空方块下边            //往上移动            translateAnimation = new TranslateAnimation(0.1f , -imageView.getWidth(), 0.1f , 0.1f );        }else if ( imageView.getX() < iv_null.getX() ){ //当前点击的方块在空方块上边            //往下移动            translateAnimation = new TranslateAnimation(0.1f , imageView.getWidth(), 0.1f , 0.1f );        }else if ( imageView.getY() > iv_null.getY() ){ //当前点击的方块在空方块右边            //往左移动            translateAnimation = new TranslateAnimation(0.1f , 0.1f , 0.1f , -imageView.getWidth() );        } else if ( imageView.getY() < iv_null.getY() ){ //当前点击的方块在空方块左边            //往右移动            translateAnimation = new TranslateAnimation(0.1f , 0.1f , 0.1f , imageView.getWidth() );        }        //设置动画的时长        translateAnimation.setDuration(70);        //设置动画结束后是否停留        translateAnimation.setFillAfter(true);        //动画结束后交换数据        translateAnimation.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                imageView.clearAnimation();                GameData mGameData = (GameData) imageView.getTag();                iv_null.setImageBitmap(mGameData.bm);                GameData mNullGameData = (GameData) iv_null.getTag();                mNullGameData.bm = mGameData.bm ;                mNullGameData.p_x = mGameData.p_x ;                mNullGameData.p_y = mGameData.p_y ;                //设置当前点击的方块为空方块                setNullImageView(imageView);                if( isGameStart){                    isGameOver();                }            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });        //执行动画        imageView.startAnimation(translateAnimation);    }    /**     * 设置某个方块为空方块     * @param imageView 当前要设置为空的方块的实例     */    public void setNullImageView( ImageView imageView){        imageView.setImageBitmap(null);        iv_null = imageView ;    }    /**     * 判读当前点击的方块与空白方块是否相邻     * @param imageView 所点击的方块     * @return true 相邻     */    public boolean isNearNullImageView( ImageView imageView){        //分别获取当前空方块与点击方块的位置,通过想x,y两边都差1的方式判断        GameData mNullGameData = (GameData) iv_null.getTag();        GameData mGameData = (GameData) imageView.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) {            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;        }    }    //判断游戏结束的方法    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 ){                    continue;                }                GameData mGameData = (GameData) iv_game_arr[i][j].getTag();                if( !mGameData.isTrue()){                    isGameOver = false ;                    break ;                }            }        }        if( isGameOver ){            Toast.makeText(this,"游戏结束",Toast.LENGTH_SHORT).show();        }    }}

布局文件就是一个简单的GridLayout

<?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:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.pintu.MainActivity">    <GridLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:columnCount="5"        android:rowCount="3"        android:id="@+id/gl_main_game">GridLayout>RelativeLayout>

更多相关文章

  1. 关于Android中的位置服务解读
  2. Android(安卓)Studio 完美修改应用包名
  3. Android(安卓)GPS定位步骤
  4. 切换tab的时候recyclerview滑动到最底部
  5. Android(安卓)SDK Manager无法更新问题解决办法
  6. Android(安卓)GPS学习
  7. Android中广告条轮播(Banner)的实现
  8. Android滑动手势侦测方法
  9. Android下的RTSP客户端搭建

随机推荐

  1. Android(安卓)移植到 C#
  2. unity在android真机上的调试
  3. 论Android(安卓)Binder驱动在Framework中
  4. Android处理大图片
  5. Android(安卓)Animation学习笔记
  6. android vsnc 工作原理
  7. Android(安卓)NDK: Host 'awk' tool is o
  8. Launcher的启动过程
  9. Android触摸事件机制
  10. (Android)Activity的生命的周期