Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android拼圖游戲的設計邏輯,實例提高!

Android拼圖游戲的設計邏輯,實例提高!

編輯:關於Android編程

 

群英傳的最後一章,我大致的看了一下這個例子,發現鴻洋大神也做過,就參考兩個人的設計邏輯,感覺都差不多,就這樣實現起來了

一.切圖工具類

我們九宮格嘛,肯定要一個切圖的工具,把一個圖片給切成九張,那具體是怎麼實現呢?我們先寫一個bean來存儲一切的狀態

ImagePiece

package com.lgl.ninegame.utils;

import android.graphics.Bitmap;

/**
 *
 * Created by LGL on 2016/5/2.
 */
public class ImagePiece {

    private int index;
    private Bitmap bitmap;

    //構造方法
    public ImagePiece() {

    }

    //有參構造方法
    public ImagePiece(int index, Bitmap bitmap) {
        this.index = index;
        this.bitmap = bitmap;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public Bitmap getBitmap() {
        return bitmap;
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

}

然後就可以實現我們的切圖工具類了

ImageSplitterUtil

package com.lgl.ninegame.utils;

import android.graphics.Bitmap;

import java.util.ArrayList;
import java.util.List;

/**
 * 切圖工具
 * Created by LGL on 2016/5/2.
 */
public class ImageSplitterUtil {

    /**
     * 靜態方法
     * 傳遞bitmap切成piece*piece塊,返回List
     *
     * @param bitmap
     * @param piece
     * @return
     */
    public static List splitImage(Bitmap bitmap, int piece) {

        //作為返回值傳遞
        List imagePieces = new ArrayList<>();

        //獲取圖片的寬高
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        //根據寬高取最小值達到正方形
        int pieceWidth = Math.min(width, height) / piece;

        //進行切割
        for (int i = 0; i < piece; i++) {
            for (int j = 0; j < piece; j++) {
                ImagePiece imagePiece = new ImagePiece();
                imagePiece.setIndex(j + i * piece);

                int x = j * pieceWidth;
                int y = i * pieceWidth;

                //第一次循環為0,0,
                imagePiece.setBitmap(Bitmap.createBitmap(bitmap, x, y, pieceWidth, pieceWidth));
                /**
                 * 保存到list中進行返回
                 */
                imagePieces.add(imagePiece);
            }
        }
        return imagePieces;
    }


}

二.自定義容器

工具有了,就需要容器了,我們需要自定義一個,這裡我們就繼承相對布局,我們這個是一個游戲布局,所以我實現准備好了一張妹子的圖片,分辨率是800*80

這裡寫圖片描述

GameView

package com.lgl.ninegame.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.lgl.ninegame.R;
import com.lgl.ninegame.utils.ImagePiece;
import com.lgl.ninegame.utils.ImageSplitterUtil;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 自定義容器
 * Created by LGL on 2016/5/2.
 */
public class GameView extends RelativeLayout implements View.OnClickListener {


    //默認3*3
    private int mColumn = 3;
    //容器的內邊距
    private int mPadding;
    //小圖的距離 dp
    private int mMagin = 3;
    //存儲圖片的,寬高 都是固定的,所以使用數組
    private ImageView[] mGameOintuItems;
    //寬度
    private int mItemWidth;
    //圖片
    private Bitmap mBitmap;
    //切圖後存儲
    private List mItemBitmaps;
    //標記
    private boolean once;

    //容器的一個寬度
    private int mWidth;


    public GameView(Context context) {

        this(context, null);
    }

    public GameView(Context context, AttributeSet attrs) {

        this(context, attrs, 0);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    /**
     * 初始化
     */
    private void init() {
        //單位轉換——dp-px
        mMagin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, getResources().getDisplayMetrics());

        mPadding = min(getPaddingLeft(), getPaddingRight(), getPaddingTop(), getPaddingBottom());
    }

    /**
     * 確定當前布局的大小,我們要設置成正方形
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //拿到容器的高寬最小值
        mWidth = Math.min(getMeasuredHeight(), getMeasuredWidth());

        if (!once) {
            //進行切圖和排序
            initBitmap();

            //設置imageview(item)的寬高等屬性
            initItem();

            once = true;

        }
        setMeasuredDimension(mWidth, mWidth);
    }

    /**
     * 進行切圖和排序
     */
    private void initBitmap() {
        //判斷是否存在這張圖片
        if (mBitmap == null) {
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img);
        }
        //進行裁剪
        mItemBitmaps = ImageSplitterUtil.splitImage(mBitmap, mColumn);

        //裁剪玩後需要進行順序打亂sort
        Collections.sort(mItemBitmaps, new Comparator() {
            @Override
            public int compare(ImagePiece lhs, ImagePiece rhs) {

                //生成隨機數,如果》0.5返回1否則返回-1
                return Math.random() > 0.5 ? 1 : -1;
            }
        });

    }

    /**
     * 設置imageview(item)的寬高等屬性
     */
    private void initItem() {
        //( 容器的寬度 - 內邊距 * 2  - 間距  ) /  裁剪的數量
        mItemWidth = (mWidth - mPadding * 2 - mMagin * (mColumn - 1)) / mColumn;
        //幾 * 幾
        mGameOintuItems = new ImageView[mColumn * mColumn];

        //開始排放
        for (int i = 0; i < mGameOintuItems.length; i++) {
            ImageView item = new ImageView(getContext());
            item.setOnClickListener(this);
            //設置圖片
            item.setImageBitmap(mItemBitmaps.get(i).getBitmap());
            //保存
            mGameOintuItems[i] = item;
            //設置ID
            item.setId(i + 1);
            //設置Tag
            item.setTag(i + "_" + mItemBitmaps.get(i).getIndex());

            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(mItemWidth, mItemWidth);

            //判斷不是最後一列
            if (i + 1 % mColumn != 0) {
                lp.rightMargin = mMagin;
            }

            //判斷不是第一列
            if (i % mColumn != 0) {
                lp.addRule(RelativeLayout.RIGHT_OF, mGameOintuItems[i - 1].getId());
            }

            //判斷如果不是第一行
            if ((i + 1) > mColumn) {
                lp.topMargin = mMagin;
                lp.addRule(RelativeLayout.BELOW, mGameOintuItems[i - mColumn].getId());
            }
            addView(item, lp);
        }
    }

    /**
     * 獲取多個參數的最小值
     */
    private int min(int... params) {
        int min = params[0];
        //遍歷
        for (int param : params) {
            if (param < min) {
                min = param;
            }
        }
        return min;
    }

    /**
     * 點擊事件
     *
     * @param v
     */
    @Override
    public void onClick(View v) {

    }
}

代碼的邏輯十分的簡單,這點不假,而且注釋也是相對來講清晰易懂,這樣,我們先測試一下,在XML中引用




    



我們運行一下看看現在裁剪後的效果

這裡寫圖片描述

可以的,那我們繼續

三.實現圖片交互

這裡大家應該都知道,要用我們的點擊事件了,我們繼續在GameView裡面編寫

 /**
     * 點擊的第一張圖和第二張圖,他們進行交換
     */
    private ImageView mFirst;
    private ImageView mSecond;

    /**
     * 點擊事件
     *
     * @param v
     */
    @Override
    public void onClick(View v) {

        //重復點擊
        if (mFirst == v) {
            //去掉顏色
            mFirst.setColorFilter(null);
            mFirst = null;
            return;
        }

        if (mFirst == null) {
            mFirst = (ImageView) v;
            //設置選中效果
            mFirst.setColorFilter(Color.parseColor("#55FF0000"));
            //第二次點擊
        } else {
            mSecond = (ImageView) v;
            //交換
            exchangeView();
        }
    }

這裡我們需要去寫一個圖片交換的方法

 /**
     * 圖片交換
     */
    private void exchangeView() {
        //先去掉顏色
        mFirst.setColorFilter(null);

        String firstTag = (String) mFirst.getTag();
        String secondTag = (String) mSecond.getTag();

        String[] firstParams = firstTag.split("_");
        String[] scendParams = secondTag.split("_");

        //獲取到bitmap並且替換
        mSecond.setImageBitmap(mItemBitmaps.get(Integer.parseInt(firstParams[0])).getBitmap());
        mFirst.setImageBitmap(mItemBitmaps.get(Integer.parseInt(scendParams[0])).getBitmap());

        //回到最初始的狀態
        mFirst = mSecond = null;

    }

這樣,我們就可以運行了

這裡寫圖片描述

但是,大家有沒有發現,他的小bitmap排序是錯誤的,這就需要我們去處理了<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCgk8cD7KtbzKyc/Kx9LyzqrO0sPHy+TIu727u7vBy6OstavKx3RhZ8O7uMSjrM7Sw8fU2rvYtb3X7rP1yry1xNe0zKzWrsewvNPJz9LUz8K0+sLro7o8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cHJlIGNsYXNzPQ=="brush:java;"> //改變tag mFirst.setTag(secondTag); mSecond.setTag(firstTag);

四.交互動畫

既然我們卡片已經實現了,那麼接下來,我們怎麼的也要去加點動畫呀,開搞,我們先把公用的東西抽取出來

 /**
     * 獲取tag
     *
     * @param tag
     * @return
     */
    public int getImageIdByTag(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[0]);
    }

    /**
     * 獲取圖片的tag
     *
     * @param tag
     * @return
     */
    public int getImageIndex(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[1]);
    }

    /**
     * 動畫層,覆蓋在viewGroup中
     */
    private RelativeLayout mAnimLayout;


    /**
     * 交互動畫
     */
    private void setUpAnimLayout() {
        if (mAnimLayout == null) {
            mAnimLayout = new RelativeLayout(getContext());
            //添加到整體
            addView(mAnimLayout);
        }
    }

接著,我們需要修改以下圖片交換的方法,添加一層動畫層

/**
     * 圖片交換
     */
    private void exchangeView() {
        mFirst.setColorFilter(null);
        // 構造我們的動畫層
        setUpAnimLayout();

        ImageView first = new ImageView(getContext());
        final Bitmap firstBitmap = mItemBitmaps.get(
                getImageIdByTag((String) mFirst.getTag())).getBitmap();
        first.setImageBitmap(firstBitmap);
        LayoutParams lp = new LayoutParams(mItemWidth, mItemWidth);
        lp.leftMargin = mFirst.getLeft() - mPadding;
        lp.topMargin = mFirst.getTop() - mPadding;
        first.setLayoutParams(lp);
        mAnimLayout.addView(first);

        ImageView second = new ImageView(getContext());
        final Bitmap secondBitmap = mItemBitmaps.get(
                getImageIdByTag((String) mSecond.getTag())).getBitmap();
        second.setImageBitmap(secondBitmap);
        LayoutParams lp2 = new LayoutParams(mItemWidth, mItemWidth);
        lp2.leftMargin = mSecond.getLeft() - mPadding;
        lp2.topMargin = mSecond.getTop() - mPadding;
        second.setLayoutParams(lp2);
        mAnimLayout.addView(second);

        // 設置動畫
        TranslateAnimation anim = new TranslateAnimation(0, mSecond.getLeft()
                - mFirst.getLeft(), 0, mSecond.getTop() - mFirst.getTop());
        anim.setDuration(300);
        anim.setFillAfter(true);
        first.startAnimation(anim);

        TranslateAnimation animSecond = new TranslateAnimation(0,
                -mSecond.getLeft() + mFirst.getLeft(), 0, -mSecond.getTop()
                + mFirst.getTop());
        animSecond.setDuration(300);
        animSecond.setFillAfter(true);
        second.startAnimation(animSecond);

        // 監聽動畫
        anim.setAnimationListener(new Animation.AnimationListener()
        {
            @Override
            public void onAnimationStart(Animation animation)
            {
                mFirst.setVisibility(View.INVISIBLE);
                mSecond.setVisibility(View.INVISIBLE);

            }

            @Override
            public void onAnimationRepeat(Animation animation)
            {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation)
            {

                String firstTag = (String) mFirst.getTag();
                String secondTag = (String) mSecond.getTag();

                mFirst.setImageBitmap(secondBitmap);
                mSecond.setImageBitmap(firstBitmap);

                mFirst.setTag(secondTag);
                mSecond.setTag(firstTag);

                mFirst.setVisibility(View.VISIBLE);
                mSecond.setVisibility(View.VISIBLE);

                mFirst = mSecond = null;
                mAnimLayout.removeAllViews();
            }
        });
    }

這樣,我們就可以有動畫效果了,我們來運行一下

這裡寫圖片描述

到現在,我們就已經可以玩了,但是這樣子就不叫游戲了,我們應該這樣添加一些過關的邏輯

五.過關邏輯

其實過關的邏輯很簡單的,只要我們在每次移動之後去判斷是不是過關了就行,如下代碼

 /**
     * 判斷是否過關
     */
    private void checkSuccess() {
        boolean isSuccess = true;

        for (int i = 0; i < mGameOintuItems.length; i++) {
            //拿到所有的圖片
            ImageView imageView  = mGameOintuItems[i];

            if(getImageIndex((String) imageView.getTag()) != i){
                isSuccess = false;
            }
        }
        if(isSuccess){
            Log.i("tag","成功");
            Toast.makeText(getContext(),"成功,進入下一關!",Toast.LENGTH_LONG).show();
        }
    }

OK,但是這個不是重點,重點是我們要下一關,而且要把相應的數據傳遞給MainActivity,這就要實現接口了

 private static final int TIME_CHANGED = 10;
    private static final int NEXT_LEVEL = 11;

    /**
     * 設置接口回調
     *
     * @param mListener
     */
    public void setOnGamemListener(GamePintuListener mListener) {

        this.mListener = mListener;
    }

    public GamePintuListener mListener;

    /**
     * 關數
     */
    private int level = 1;

    /**
     * 設置開啟時間
     *
     * @param timeEnabled
     */
    public void setTimeEnabled(boolean timeEnabled) {
        isTimeEnabled = timeEnabled;
    }

    //接口
    private interface GamePintuListener {
        //關卡
        void nextLevel(int nextLevel);

        //時間
        void timechanged(int time);

        //游戲結束
        void gameOver();
    }

同時要實現下一關的方法

 /**
     * 下一關
     */
    public void nextLevel() {
        this.removeAllViews();
        mAnimLayout = null;
        mColumn++;
        isGameSuccess = false;
        initBitmap();
        initItem();
    }

這樣,我們就可以在handler中操作了

//子線程操作
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case TIME_CHANGED:

                    break;
                case NEXT_LEVEL:

                    level = level + 1;

                    if(mListener!=null){

                        mListener.nextLevel(level);
                    }else{
                        nextLevel();
                    }
                    break;
            }
            super.handleMessage(msg);
        }
    };

這邊的邏輯OK了之後,我們需要回到MainActivity去操作顯示UI

gameview = (GameView) findViewById(R.id.gameview);
        gameview.setOnGamemListener(new GameView.GamePintuListener() {
            @Override
            public void nextLevel(int nextLevel) {

                new AlertDialog.Builder(MainActivity.this).setTitle("拼圖完成").setMessage("美女抱回家").setPositiveButton("下一關", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        gameview.nextLevel();
                    }
                }).show();
            }

            @Override
            public void timechanged(int time) {

            }

            @Override
            public void gameOver() {

            }
        });

這樣,我們再來演示一遍

這裡寫圖片描述

六.記錄時間

開發也到了最後了,我們把時間記錄給實現了,我們還是的創建幾個方法

/**
     * 是否顯示時間
     */
    private void checkTimeEnable() {
        //如果我們開啟了
        if (isTimeEnabled) {
            countTimeBaseLevel();
            handler.sendEmptyMessage(TIME_CHANGED);
        }
    }

    /**
     * 根據當前等級設置時間
     */
    private void countTimeBaseLevel() {
        mTime = (int) Math.pow(2, level) * 60;
    }

然後發送handler

                 case TIME_CHANGED:
                    if (isGameSuccess || isGameOver) {
                        return;
                    }

                    if (mListener != null) {
                        mListener.timechanged(mTime);
                        if (mTime == 0) {
                            isGameOver = true;
                            mListener.gameOver();
                            return;
                        }
                    }
                    mTime--;
                    handler.sendEmptyMessageDelayed(TIME_CHANGED, 1000);

                    break;

現在我們可以去MainActivityity實現邏輯了,這裡的gameover邏輯可以這樣下

@Override
            public void gameOver() {
                new AlertDialog.Builder(MainActivity.this).setTitle("游戲結束").setMessage("很遺憾沒有成功抱到美女!").setPositiveButton("重新開始", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //先不考慮
                    }
                }).setNegativeButton("退出", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                }).show();
            }
        });

時間

          @Override
            public void timechanged(int time) {
                //設置時間
                tv_time.setText("倒計時:"+time);
            }

這裡要記住設置顯示效果

 //顯示時間
 gameview.setTimeEnabled(true);

現在就可以倒計時了,同時,也可以監聽到結束了

這裡寫圖片描述

七.最後的補充

我們gameover以後也是需要操作的,我們有一個重新開始,我們只要寫一個初始化的方法就可以了

    /**
     * 重新開始
     */
    public void restartGame() {
        isGameOver = false;
        mColumn--;
        nextLevel();

    }

這樣就可以了

當然,我們游戲一般都是有暫停的,這個我們也加上,我們在GameView中新建方法

 /**
     * 暫停
     */
    public void pauseGame() {
        isPause = true;
        handler.removeMessages(TIME_CHANGED);
    }


    /**
     * 恢復
     */
    public void resumeGame() {
        if (isPause) {
            isPause = false;
            handler.sendEmptyMessage(TIME_CHANGED);
        }
    }

不過我們的目的是他後台時=不記錄時間,所以只要和生命周期綁定就可以了


    @Override
    protected void onPause() {
        super.onPause();
        gameview.pauseGame();
    }

    @Override
    protected void onResume() {
        super.onResume();
        gameview.resumeGame();
    }

到這裡,整個游戲算是正式的開發完整了,貼上完整的代碼

MainActivity

package com.lgl.ninegame;

import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.lgl.ninegame.view.GameView;

public class MainActivity extends AppCompatActivity {

    private GameView gameview;

    private TextView tv_level, tv_time;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv_level = (TextView) findViewById(R.id.tv_level);
        tv_time = (TextView) findViewById(R.id.tv_time);

        gameview = (GameView) findViewById(R.id.gameview);

        //顯示時間
        gameview.setTimeEnabled(true);

        gameview.setOnGamemListener(new GameView.GamePintuListener() {
            @Override
            public void nextLevel(final int nextLevel) {

                new AlertDialog.Builder(MainActivity.this).setTitle("拼圖完成").setMessage("美女抱回家").setPositiveButton("下一關", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        gameview.nextLevel();
                        tv_level.setText("當前關卡" + nextLevel);
                    }
                }).show();
            }

            @Override
            public void timechanged(int time) {
                //設置時間
                tv_time.setText("倒計時:" + time);
            }

            @Override
            public void gameOver() {
                new AlertDialog.Builder(MainActivity.this).setTitle("游戲結束").setMessage("很遺憾沒有成功抱到美女!").setPositiveButton("重新開始", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        gameview.restartGame();
                    }
                }).setNegativeButton("退出", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                }).show();
            }
        });
    }


    @Override
    protected void onPause() {
        super.onPause();
        gameview.pauseGame();
    }

    @Override
    protected void onResume() {
        super.onResume();
        gameview.resumeGame();
    }
}

GameView

package com.lgl.ninegame.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.lgl.ninegame.R;
import com.lgl.ninegame.utils.ImagePiece;
import com.lgl.ninegame.utils.ImageSplitterUtil;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 自定義容器
 * Created by LGL on 2016/5/2.
 */
public class GameView extends RelativeLayout implements View.OnClickListener {


    //默認3*3
    private int mColumn = 3;
    //容器的內邊距
    private int mPadding;
    //小圖的距離 dp
    private int mMagin = 3;
    //存儲圖片的,寬高 都是固定的,所以使用數組
    private ImageView[] mGameOintuItems;
    //寬度
    private int mItemWidth;
    //圖片
    private Bitmap mBitmap;
    //切圖後存儲
    private List mItemBitmaps;
    //標記
    private boolean once;

    //記錄時間
    private int mTime;

    //容器的一個寬度
    private int mWidth;

    //判斷游戲是否成功
    private boolean isGameSuccess;

    //是否顯示時間
    private boolean isTimeEnabled = false;

    /**
     * 動畫層,覆蓋在viewGroup中
     */
    private RelativeLayout mAnimLayout;

    private boolean isGameOver;
    /**
     * 動畫限制
     */
    private boolean isAniming;

    private static final int TIME_CHANGED = 10;
    private static final int NEXT_LEVEL = 11;

    /**
     * 設置接口回調
     *
     * @param mListener
     */
    public void setOnGamemListener(GamePintuListener mListener) {

        this.mListener = mListener;
    }

    public GamePintuListener mListener;

    /**
     * 關數
     */
    private int level = 1;

    /**
     * 設置開啟時間
     *
     * @param timeEnabled
     */
    public void setTimeEnabled(boolean timeEnabled) {
        isTimeEnabled = timeEnabled;
    }

    //接口
    public interface GamePintuListener {
        //關卡
        void nextLevel(int nextLevel);

        //時間
        void timechanged(int time);

        //游戲結束
        void gameOver();
    }

    //子線程操作
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case TIME_CHANGED:
                    if (isGameSuccess || isGameOver || isPause) {
                        return;
                    }

                    if (mListener != null) {
                        mListener.timechanged(mTime);
                        if (mTime == 0) {
                            isGameOver = true;
                            mListener.gameOver();
                            return;
                        }
                    }
                    mTime--;
                    handler.sendEmptyMessageDelayed(TIME_CHANGED, 1000);

                    break;
                case NEXT_LEVEL:

                    level = level + 1;

                    if (mListener != null) {

                        mListener.nextLevel(level);
                    } else {
                        nextLevel();
                    }
                    break;
            }
            super.handleMessage(msg);
        }
    };


    public GameView(Context context) {

        this(context, null);
    }

    public GameView(Context context, AttributeSet attrs) {

        this(context, attrs, 0);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    /**
     * 初始化
     */
    private void init() {
        //單位轉換——dp-px
        mMagin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, getResources().getDisplayMetrics());

        mPadding = min(getPaddingLeft(), getPaddingRight(), getPaddingTop(), getPaddingBottom());
    }

    /**
     * 確定當前布局的大小,我們要設置成正方形
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //拿到容器的高寬最小值
        mWidth = Math.min(getMeasuredHeight(), getMeasuredWidth());

        if (!once) {
            //進行切圖和排序
            initBitmap();

            //設置imageview(item)的寬高等屬性
            initItem();

            //根據關卡設置時間
            checkTimeEnable();

            once = true;

        }
        setMeasuredDimension(mWidth, mWidth);
    }

    /**
     * 是否顯示時間
     */
    private void checkTimeEnable() {
        //如果我們開啟了
        if (isTimeEnabled) {
            countTimeBaseLevel();
            handler.sendEmptyMessage(TIME_CHANGED);
        }
    }

    /**
     * 根據當前等級設置時間
     */
    private void countTimeBaseLevel() {
        mTime = (int) Math.pow(2, level) * 60;
    }

    /**
     * 進行切圖和排序
     */
    private void initBitmap() {
        //判斷是否存在這張圖片
        if (mBitmap == null) {
            mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img);
        }
        //進行裁剪
        mItemBitmaps = ImageSplitterUtil.splitImage(mBitmap, mColumn);

        //裁剪玩後需要進行順序打亂sort
        Collections.sort(mItemBitmaps, new Comparator() {
            @Override
            public int compare(ImagePiece lhs, ImagePiece rhs) {

                //生成隨機數,如果》0.5返回1否則返回-1
                return Math.random() > 0.5 ? 1 : -1;
            }
        });

    }

    /**
     * 設置imageview(item)的寬高等屬性
     */
    private void initItem() {
        //( 容器的寬度 - 內邊距 * 2  - 間距  ) /  裁剪的數量
        mItemWidth = (mWidth - mPadding * 2 - mMagin * (mColumn - 1)) / mColumn;
        //幾 * 幾
        mGameOintuItems = new ImageView[mColumn * mColumn];

        //開始排放
        for (int i = 0; i < mGameOintuItems.length; i++) {
            ImageView item = new ImageView(getContext());
            item.setOnClickListener(this);
            //設置圖片
            item.setImageBitmap(mItemBitmaps.get(i).getBitmap());
            //保存
            mGameOintuItems[i] = item;
            //設置ID
            item.setId(i + 1);
            //設置Tag
            item.setTag(i + "_" + mItemBitmaps.get(i).getIndex());

            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(mItemWidth, mItemWidth);

            //判斷不是最後一列
            if (i + 1 % mColumn != 0) {
                lp.rightMargin = mMagin;
            }

            //判斷不是第一列
            if (i % mColumn != 0) {
                lp.addRule(RelativeLayout.RIGHT_OF, mGameOintuItems[i - 1].getId());
            }

            //判斷如果不是第一行
            if ((i + 1) > mColumn) {
                lp.topMargin = mMagin;
                lp.addRule(RelativeLayout.BELOW, mGameOintuItems[i - mColumn].getId());
            }
            addView(item, lp);
        }
    }

    /**
     * 獲取多個參數的最小值
     */
    private int min(int... params) {
        int min = params[0];
        //遍歷
        for (int param : params) {
            if (param < min) {
                min = param;
            }
        }
        return min;
    }

    /**
     * 點擊的第一張圖和第二張圖,他們進行交換
     */
    private ImageView mFirst;
    private ImageView mSecond;

    /**
     * 點擊事件
     *
     * @param v
     */
    @Override
    public void onClick(View v) {
        //如果點擊了一次,你還點擊,則無效
        if (isAniming) {
            return;
        }

        //重復點擊
        if (mFirst == v) {
            //去掉顏色
            mFirst.setColorFilter(null);
            mFirst = null;
            return;
        }

        if (mFirst == null) {
            mFirst = (ImageView) v;
            //設置選中效果
            mFirst.setColorFilter(Color.parseColor("#55FF0000"));
            //第二次點擊
        } else {
            mSecond = (ImageView) v;
            //交換
            exchangeView();
        }
    }

    /**
     * 圖片交換
     */
    private void exchangeView() {
        mFirst.setColorFilter(null);
        // 構造我們的動畫層
        setUpAnimLayout();

        ImageView first = new ImageView(getContext());
        final Bitmap firstBitmap = mItemBitmaps.get(
                getImageIdByTag((String) mFirst.getTag())).getBitmap();
        first.setImageBitmap(firstBitmap);
        LayoutParams lp = new LayoutParams(mItemWidth, mItemWidth);
        lp.leftMargin = mFirst.getLeft() - mPadding;
        lp.topMargin = mFirst.getTop() - mPadding;
        first.setLayoutParams(lp);
        mAnimLayout.addView(first);

        ImageView second = new ImageView(getContext());
        final Bitmap secondBitmap = mItemBitmaps.get(
                getImageIdByTag((String) mSecond.getTag())).getBitmap();
        second.setImageBitmap(secondBitmap);
        LayoutParams lp2 = new LayoutParams(mItemWidth, mItemWidth);
        lp2.leftMargin = mSecond.getLeft() - mPadding;
        lp2.topMargin = mSecond.getTop() - mPadding;
        second.setLayoutParams(lp2);
        mAnimLayout.addView(second);

        // 設置動畫
        TranslateAnimation anim = new TranslateAnimation(0, mSecond.getLeft()
                - mFirst.getLeft(), 0, mSecond.getTop() - mFirst.getTop());
        anim.setDuration(300);
        anim.setFillAfter(true);
        first.startAnimation(anim);

        TranslateAnimation animSecond = new TranslateAnimation(0,
                -mSecond.getLeft() + mFirst.getLeft(), 0, -mSecond.getTop()
                + mFirst.getTop());
        animSecond.setDuration(300);
        animSecond.setFillAfter(true);
        second.startAnimation(animSecond);

        // 監聽動畫
        anim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mFirst.setVisibility(View.INVISIBLE);
                mSecond.setVisibility(View.INVISIBLE);

                isAniming = true;
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {

                String firstTag = (String) mFirst.getTag();
                String secondTag = (String) mSecond.getTag();

                mFirst.setImageBitmap(secondBitmap);
                mSecond.setImageBitmap(firstBitmap);

                mFirst.setTag(secondTag);
                mSecond.setTag(firstTag);

                mFirst.setVisibility(View.VISIBLE);
                mSecond.setVisibility(View.VISIBLE);

                mFirst = mSecond = null;
                mAnimLayout.removeAllViews();

                //每次移動完成判斷是否過關
                checkSuccess();

                isAniming = false;
            }
        });
    }

    /**
     * 判斷是否過關
     */
    private void checkSuccess() {
        boolean isSuccess = true;

        for (int i = 0; i < mGameOintuItems.length; i++) {
            //拿到所有的圖片
            ImageView imageView = mGameOintuItems[i];

            if (getImageIndex((String) imageView.getTag()) != i) {
                isSuccess = false;
            }
        }
        if (isSuccess) {

            isGameSuccess = true;

            handler.removeMessages(TIME_CHANGED);

            Log.i("tag", "成功");
            Toast.makeText(getContext(), "成功,進入下一關!", Toast.LENGTH_LONG).show();
            handler.sendEmptyMessage(NEXT_LEVEL);

        }
    }


    /**
     * 獲取tag
     *
     * @param tag
     * @return
     */
    public int getImageIdByTag(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[0]);
    }

    /**
     * 獲取圖片的tag
     *
     * @param tag
     * @return
     */
    public int getImageIndex(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[1]);
    }

    /**
     * 交互動畫
     */
    private void setUpAnimLayout() {
        if (mAnimLayout == null) {
            mAnimLayout = new RelativeLayout(getContext());
            //添加到整體
            addView(mAnimLayout);
        }
    }

    /**
     * 下一關
     */
    public void nextLevel() {
        this.removeAllViews();
        mAnimLayout = null;
        mColumn++;
        isGameSuccess = false;
        checkTimeEnable();
        initBitmap();
        initItem();
    }

    /**
     * 重新開始
     */
    public void restartGame() {
        isGameOver = false;
        mColumn--;
        nextLevel();

    }

    //暫停狀態
    private boolean isPause;

    /**
     * 暫停
     */
    public void pauseGame() {
        isPause = true;
        handler.removeMessages(TIME_CHANGED);
    }


    /**
     * 恢復
     */
    public void resumeGame() {
        if (isPause) {
            isPause = false;
            handler.sendEmptyMessage(TIME_CHANGED);
        }
    }
}

我們最終的運行結果

這裡寫圖片描述

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved