前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >美女拼图小游戏

美女拼图小游戏

作者头像
提莫队长
发布2019-02-21 10:45:13
9330
发布2019-02-21 10:45:13
举报
文章被收录于专栏:刘晓杰

先看一下效果然后贴代码

这里写图片描述
这里写图片描述

最上面是自定义的ActionBar,布局里面有两个TextView。一个用于显示level,一个用于显示倒计时 下面就是自定义的RelativeLayout。用于显示九个一打乱的bitmap

接下来就是代码: 首先是将图片分割的工具类 ImageUtil.java

代码语言:javascript
复制
package com.example.util;

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

import android.graphics.Bitmap;

public class ImageUtil {
    /*
     * 将图片分成piece*piece份小图片,每份就是ImagePiece,存在imgList里面
     */
    public static List<ImagePiece> splitImage(Bitmap bitmap, int piece) {
        List<ImagePiece> imgList = new ArrayList<ImagePiece>();

        //每张图片的宽高
        int pieceWidth = bitmap.getWidth() / piece;
        int pieceHeight = bitmap.getHeight() / 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 * pieceHeight;

                imagePiece.setBitmap(Bitmap.createBitmap(bitmap, x, y,
                        pieceWidth, pieceHeight));

                imgList.add(imagePiece);
            }
        }

        return imgList;
    }
}

分割后的每一个ImagePiece的实体类 ImagePiece.java

代码语言:javascript
复制
package com.example.util;

import android.graphics.Bitmap;

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;
    }

    @Override
    public String toString() {
        return "ImagePiece [index=" + index + ", bitmap=" + bitmap + "]";
    }
}

接下来是自定义的GameLayout.java

代码语言:javascript
复制
package com.example.view;

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

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.TypedValue;
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.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.example.pintu.R;
import com.example.util.ImagePiece;
import com.example.util.ImageUtil;

public class GameLayout extends RelativeLayout implements OnClickListener {
    private int GameLayoutWidth;
    private int GameLayoutHeight;
    private int column;
    private int padding;// 类似于xml中的android:padding
    private int margin;// 类似于xml中的android:layout_margin
    private ImageView[] gameItem;
    private int itemWidth;
    private int itemHeight;

    private Bitmap bitmap;
    private List<ImagePiece> imgList;

    private boolean once;

    public GameLayout(Context context) {
        super(context);
        init();
    }

    public GameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    // 初始化参数
    private void init() {
        column = 3;

        margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                2, getResources().getDisplayMetrics());

        padding = min(getPaddingLeft(), getPaddingRight(), getPaddingTop(),
                getPaddingBottom());

        once = false;
    }

    private int min(int... params) {
        int min = params[0];
        for (int param : params) {
            min = Math.min(min, param);
        }
        return min;
    }

    @Override
    // onMeasure和onLayout会多次调用,所有要有once标识符
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (!once) {
            GameLayoutHeight = getMeasuredHeight();
            GameLayoutWidth = getMeasuredWidth();

            // 进行切图,并打乱次序
            initBitmap();
            // 九宫格的绘制
            initItem();
            // 判断是否开启时间
            checkTimeEnable();

            once = true;
        }

        setMeasuredDimension(GameLayoutWidth, GameLayoutHeight);
    }

    // 进行切图,并排序
    private void initBitmap() {
        // 获取bitmap,然后转化为和屏幕一样大小
        if (bitmap == null) {
            bitmap = BitmapFactory.decodeResource(getResources(),
                    R.drawable.girl);
            bitmap = Bitmap.createScaledBitmap(bitmap, GameLayoutWidth,
                    GameLayoutHeight, true);
        }
        // 切图
        imgList = ImageUtil.splitImage(bitmap, column);
        // 使用sort打乱次序
        Collections.sort(imgList, new Comparator<ImagePiece>() {
            @Override
            public int compare(ImagePiece lhs, ImagePiece rhs) {
                return Math.random() > 0.5 ? 1 : -1;
            }
        });
    }

    // 九宫格的绘制
    private void initItem() {
        // 设置gameItem的宽高
        itemWidth = (GameLayoutWidth - padding * 2 - margin * (column - 1))
                / column;
        itemHeight = (GameLayoutHeight - padding * 2 - margin * (column - 1))
                / column;

        gameItem = new ImageView[column * column];

        // 设置九宫格中每个格子对应的Bitmap,id和tag以及LayoutParams
        // 最后添加到GameLayout中
        for (int i = 0; i < gameItem.length; i++) {
            ImageView item = new ImageView(getContext());
            item.setImageBitmap(imgList.get(i).getBitmap());
            item.setId(i + 1);// **********************************
            // index是本质编号,id是打乱后的编号
            item.setTag(i + "_" + imgList.get(i).getIndex());
            item.setOnClickListener(this);// 实现图片的交换

            gameItem[i] = item;

            RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
                    itemWidth, itemHeight);
            // 设置横向间距,通过leftMargin。如果不是第一列
            if ((i % column) != 0) {
                lp.leftMargin = margin;
                lp.addRule(RelativeLayout.RIGHT_OF, gameItem[i - 1].getId());
            }
            // 设置横向间距。如果不是第一行,设置topMargin和rule
            if ((i + 1) > column) {
                lp.topMargin = margin;
                lp.addRule(RelativeLayout.BELOW, gameItem[i - column].getId());
                // anchor------The id of another view to use as an anchor,
                // or a boolean value(represented as RelativeLayout.TRUE) for
                // true
                // or 0 for false). For verbs that don't refer to another
                // sibling
                // (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
                // 注意,后面的参数不能为0(0 for false),所以打星号的地方要+1
            }
            addView(item, lp);
        }
    }

    private int time;
    private boolean isTimeEnabled = false;// 默认不开启时间

    private void checkTimeEnable() {
        if (isTimeEnabled) {
            // 根据当前等级设置时间
            time = (int) Math.pow(3.0, column);
            myHandler.sendEmptyMessage(TIME_CHANGED);
        }
    }

    private ImageView mFirst;
    private ImageView mSecond;
    private boolean isAnimation = false;

    // 实现图片的交换
    @Override
    public void onClick(View v) {
        // 防止用户疯狂的点
        if (isAnimation) {
            return;
        }
        // 两次点击同一个item
        if (mFirst == v) {
            mFirst.setColorFilter(null);
            mFirst = null;
            return;
        }

        if (mFirst == null) {// 第一次点击的是新的图片
            mFirst = (ImageView) v;
            mFirst.setColorFilter(Color.parseColor("#55FF0000"));
        } else {// 第二次点击也是新的图片
            mSecond = (ImageView) v;
            exchageView();// 交换图片
        }
    }

    private RelativeLayout mAnimLayout;// 实现动画切换的变量

    // 交换图片
    private void exchageView() {
        mFirst.setColorFilter(null);

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

        final Bitmap firstBitmap = imgList.get(getImageIdByTag(firstTag))
                .getBitmap();
        final Bitmap secondBitmap = imgList.get(getImageIdByTag(secondTag))
                .getBitmap();

        // 构造动画层
        if (mAnimLayout == null) {
            mAnimLayout = new RelativeLayout(getContext());
            addView(mAnimLayout);
        }
        // 构造图片交换动画
        final ImageView first = new ImageView(getContext());
        first.setImageBitmap(firstBitmap);
        LayoutParams lp = new LayoutParams(itemWidth, itemHeight);
        lp.leftMargin = mFirst.getLeft() - padding;
        lp.topMargin = mFirst.getTop() - padding;
        first.setLayoutParams(lp);
        mAnimLayout.addView(first);

        final ImageView second = new ImageView(getContext());
        second.setImageBitmap(secondBitmap);
        LayoutParams lp2 = new LayoutParams(itemWidth, itemHeight);
        lp2.leftMargin = mSecond.getLeft() - padding;
        lp2.topMargin = mSecond.getTop() - padding;
        second.setLayoutParams(lp2);
        mAnimLayout.addView(second);

        TranslateAnimation animation = new TranslateAnimation(0,
                mSecond.getLeft() - mFirst.getLeft(), 0, mSecond.getTop()
                        - mFirst.getTop());
        animation.setDuration(300);
        animation.setFillAfter(true);
        first.startAnimation(animation);

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

        animation.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                isAnimation = true;
                mFirst.setVisibility(View.INVISIBLE);
                mSecond.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // 交换图片(注意tag也要交换)
                isAnimation = false;

                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();// 判断是否过关
            }
        });
    }

    private int getImageIdByTag(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[0]);
    }

    // item.setTag(i + "_" + imgList.get(i).getIndex());
    private int getImageIndexByTag(String tag) {
        String[] split = tag.split("_");
        return Integer.parseInt(split[1]);
    }

    // 判断是否过关。过关条件就是0到8有序排列
    private void checkSuccess() {
        boolean isSuccess = true;
        for (int i = 0; i < gameItem.length; i++) {
            ImageView imageView = gameItem[i];
            if (getImageIndexByTag((String) imageView.getTag()) != i) {
                isSuccess = false;
            }
        }
        if (isSuccess) {
            isGameSuccess = true;
            myHandler.removeMessages(TIME_CHANGED);
            Toast.makeText(getContext(), "Success ! Level Up !",
                    Toast.LENGTH_SHORT).show();
            myHandler.sendEmptyMessage(NEXT_LEVEL);// 进入下一关
        }
    }

    private static final int NEXT_LEVEL = 0x001;
    private static final int TIME_CHANGED = 0x002;
    private boolean isGameSuccess;
    private boolean isGameOver;
    private Handler myHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case NEXT_LEVEL:// 进入下一关
                column++;
                if (mListener != null) {
                    mListener.nextLevel(column);
                }
                break;
            case TIME_CHANGED:
                if (isGameSuccess || isGameOver || isPause)
                    return;
                if (mListener != null) {
                    mListener.timeChanged(time);
                    if (time == 0) {
                        isGameOver = true;
                        mListener.gameOver();
                        return;
                    }
                }
                time--;
                myHandler.sendEmptyMessageDelayed(TIME_CHANGED, 1000);
                break;
            }
        };
    };

    public void nextLevel() {
        this.removeAllViews();
        mAnimLayout = null;
        isGameSuccess = false;
        checkTimeEnable();
        initBitmap();
        initItem();
    };

    public void restart() {
        isGameOver = false;
        nextLevel();
    }
    private boolean isPause;
    public void pause(){
        isPause = true;
        myHandler.removeMessages(TIME_CHANGED);
    }

    public void resume(){
        if(isPause){
            isPause = false;
            myHandler.sendEmptyMessage(TIME_CHANGED);
        }
    }

    // 定义接口,用于通知主界面的level和time
    public interface GameListener {
        void nextLevel(int level);
        void timeChanged(int currentTime);
        void gameOver();
    }

    public GameListener mListener;

    public void setOnGameListener(GameListener Listener) {
        this.mListener = Listener;
    }

    public void setTimeEnabled(boolean isTimeEnabled) {
        this.isTimeEnabled = isTimeEnabled;
    }
}

GameLayout实现如下几个功能 1.自定义容器 2.实现图片交换onCLickListener 3.实现过关逻辑interface GameListener 4.实现游戏的结束和暂停,这需要配合activity的onPause和onResume

接下来就是MainActivity.java

代码语言:javascript
复制
package com.example.pintu;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.Window;
import android.widget.TextView;

import com.example.view.GameLayout;
import com.example.view.GameLayout.GameListener;

public class MainActivity extends Activity {
    private GameLayout gameLayout;
    private TextView levelView, timeView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 自定义ActionBar,
        // 用法参考http://blog.csdn.net/jia20003/article/details/12966489
        requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.main);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title);

        levelView = (TextView) findViewById(R.id.id_level);
        levelView.setText("level 1");
        timeView = (TextView) findViewById(R.id.id_time);

        gameLayout = (GameLayout) findViewById(R.id.pintu);
        gameLayout.setTimeEnabled(true);
        gameLayout.setOnGameListener(new GameListener() {
            @Override
            public void timeChanged(int currentTime) {
                timeView.setText("" + currentTime);
            }

            @Override
            public void nextLevel(int level) {
                new AlertDialog.Builder(MainActivity.this).setTitle("LEVEL UP")
                        .setPositiveButton("next level", new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                gameLayout.nextLevel();
                            }
                        }).show();
                // 3*3对应level 1;4*4对应level 2
                levelView.setText("level " + (level - 2));
            }

            @Override
            public void gameOver() {
                new AlertDialog.Builder(MainActivity.this)
                        .setTitle("Game Over")
                        .setPositiveButton("RESTART", new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                gameLayout.restart();
                            }
                        }).setNegativeButton("QUIT", new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                finish();
                            }
                        }).show();
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        gameLayout.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        gameLayout.resume();
    }
}

适合自定义ActionBar还要在styles.xml添加

代码语言:javascript
复制
<style name="MyTheme" parent="android:Theme.Light">  
    </style>  

以及修改AndroidManifest.xml

代码语言:javascript
复制
android:theme="@style/MyTheme"
<!--         就算MyTheme和自动生成的AppBaseTheme一样,还是要重新定义 -->
<!--         因为ActionBar布局改变了 -->

最后给出两个布局 main.xml

代码语言:javascript
复制
<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.pintu.MainActivity" >

    <com.example.view.GameLayout
        android:id="@+id/pintu"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="2dp" >
    </com.example.view.GameLayout>

</RelativeLayout>

以及自定义的actionbar的布局title.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="horizontal"
    tools:context=".MainActivity"
    android:background="#FFFFFF" >

    <TextView
        android:id="@+id/id_level"
        android:layout_width="0sp"
        android:layout_weight="1"
        android:gravity="left"
        android:textSize="20sp"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/id_time"
        android:layout_width="0sp"
        android:layout_weight="1"
        android:gravity="right"
        android:textSize="20sp"
        android:layout_height="wrap_content" />

</LinearLayout>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年04月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档