您的位置:首页 > 其它

美女拼图小游戏

2016-04-14 16:35 381 查看
先看一下效果然后贴代码



最上面是自定义的ActionBar,布局里面有两个TextView。一个用于显示level,一个用于显示倒计时

下面就是自定义的RelativeLayout。用于显示九个一打乱的bitmap

接下来就是代码:

首先是将图片分割的工具类

ImageUtil.java

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

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

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

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添加

<style name="MyTheme" parent="android:Theme.Light">
</style>


以及修改AndroidManifest.xml

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


最后给出两个布局

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="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

<?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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: