【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏_第1页
【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏_第2页
【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏_第3页
【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏_第4页
【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】怎么在Android平台中实现一个拼图小游戏

怎么在Android平台中实现一个拼图小游戏?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。一、需求描述拼图是一款益智类经典游戏了,本游戏学习了一些前辈们的经验,整体来说讲,将图片用切图工具进行切割,监听用户手指滑动事件,当用户对凌乱的图片,在一定的时间内拼凑恢复成原来的样子,则成功闯关。根据游戏不同的关卡对图片进行动态的切割。玩家可以在随意交换任意两张图片,通过遍历切割好的每块图片,将用户选中的图片,进行替换;其中主要的功能为:动态对图片进行切割成所需要的份数。玩家任意点击的两张图片能够进行正确交换。实现交换图片的动画切换效果。实现过关逻辑。实现游戏时间逻辑控制。游戏结束和暂停。二、主要功能分析在拼图游戏开发过程中,实现的主要的功能;提供给用户所使用,具体功能分析如下所示:1、编写切片工具:由于拼图游戏需要准备一个完整的图片,从直观上来看,我们不能每次都将一个完整的图片进行分割,如果是3*3,分成9块,4*4分成16份,这样带来的图片资源极大的混乱,不利于后期的维护,然后Andorid就提供了具体的方法来实现对特定图片的切图工具,通过传入的参数的不同,对图片分割成所需要的矩阵,并设置每块的宽高。利用两个for循环进行切图。并设置每块图片的大小位置和每块图片的块号下标Index。2、自定义容器:自定义相对布局文件,用来存放切割好的图片,并设置图片之间的间隙,以及确定图片上下左右的关系。以及设置图片与容器的内边距设置。3、实现图片交换:实现手指的监听事件,将对选中的两张图片进行位置的变换。4、实现交换图片的动画效果:构造动画层,设置动画,监听动画5、实现游戏过关逻辑:成功的判断,关卡的回调。6、实现游戏时间逻辑:游戏时间的更新,以及Handler不断的回调,时间超时后游戏状态的处理,以及成功闯关后,游戏时间的变更。7、游戏的结束与暂停:当用户返回主页面的时候,游戏能够暂停,当用户返回游戏的时候,游戏可以重新开始。三、概要设计1、**切图工具类**ImagePiece和ImageSplitterUtil。其中ImagePiece对Bitmap图片的块号与每一块图片的位置进行属性的基本设置;在切图工具类ImageSplitterUtil中,提供一个切图方法splitImage,将传入的Bitmap图片分割成Piece*Piece块,并设置每块宽度,将分割好的图片放入到List中。2、自定义View:GamePintuLayout.java中运用的主要工具有:单位转换:将传入的数值进行单位转换成3PX,使得屏幕可识别。//单位的转换

mMargin

=

(int)

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

3,

getResources().getDisplayMetrics());/*获取多个参数的最小值*/

private

int

min(int...

params)

{

int

min

=

params[0];

for

(int

param

:

params)

{

if

(param

<

min)

min

=

param;

}

return

min;

}3、图片乱序的实现://

使用sort完成我们的乱序

Collections.sort(mItemBitmaps,

new

Comparator<ImagePiece>()

{

public

int

compare(ImagePiece

a,

ImagePiece

b)

{

return

Math.random()

>

0.5

?

1

:

-1;

}

});4、图片的交换:在监听事件中,当用户选中了两张图片,则对图片进行交换,并对第一次选中的图片,进行样式的设置。如果用户重复点击一张图片,则消除图片的选中状态。通过给图片设置的Tag,找到Id,然后找到Bitmap图片的index,然后进行交换同时交换Tag。String

firstTag

=

(String)

mFirst.getTag();

String

secondTag

=

(String)

mSecond.getTag();

mFirst.setImageBitmap(secondBitmap);

mSecond.setImageBitmap(firstBitmap);

mFirst.setTag(secondTag);

mSecond.setTag(firstTag);5、图片动画切换:构造动画层,mAnimLayout并addView,然后在exchangeView中,先构造动画层,复制两个ImageView,为两个ImageView设置动画,监听动画的开始,让原本的View隐藏,结束以后,将图片交换,将图片显示,移除动画层。6、通过接口对关卡进行回调:实现关卡进阶、时间控制、游戏结束接口。并利用Handler更新UI,在nextLevel方法中实现移除之前的View布局,以及将动画层设置为空,增加mColumn++,然后初始化initBitmap()进行重新切图乱序并InitItem()设置图片的图片宽高。public

interface

GamePintuListener

{

void

nextLevel(int

nextLevel);

void

timechanged(int

currentTime);

void

gameover();

}

public

GamePintuListener

mListener;

/*

*

设置接口回调

*/

public

void

setOnGamePintuListener(GamePintuListener

mListener)

{

this.mListener

=

mListener;

}7、根据当前等级设置游戏的时间:mTime=(int)Math.pow(2,level)*60;进而更行我们的Handler。mHandler.sendEmptyMessageDelayed(TIME_CHANGED,1000)使得时间动态的减一。8、游戏暂停开始:mHandler.removeMessages(TIME_CHANGED);而重新开始游戏则是:mHandler.sendEmptyMessage(TIME_CHANGED);四、系统实现工具类:ImagePiece.javaImageSplitterUtil.java自定义容器:GamePintuLayout.javaImagePiece.javapackage

com.example.utils;

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;

}

public

String

toString()

{

return

"ImagePiece

[index="

+

index

+

",

bitmap="

+

bitmap

+

"]";

}

}ImageSplitterUtil.java//ImageSplitterUtil.java

package

com.example.utils;

import

java.util.ArrayList;

import

java.util.List;

import

android.graphics.Bitmap;

public

class

ImageSplitterUtil

{

/*

*

传入Bitmap切成Piece*piece块,返回List<ImagePiece>

*/

public

static

List<ImagePiece>

splitImage(Bitmap

bitmap,

int

piece)

{

List<ImagePiece>

imagePieces

=

new

ArrayList<ImagePiece>();

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;

imagePiece.setBitmap(Bitmap.createBitmap(bitmap,

x,

y,

pieceWidth,

pieceWidth));

imagePieces.add(imagePiece);

}

}

return

imagePieces;

}

}GamePintuLayout.javapackage

com.example.game_pintu.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.util.AttributeSet;

import

android.util.Log;

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.game_pintu.R;

import

com.example.utils.ImagePiece;

import

com.example.utils.ImageSplitterUtil;

public

class

GamePintuLayout

extends

RelativeLayout

implements

OnClickListener

{

private

int

mColumn

=

3;

/*

*

容器内边距

*/

private

int

mPadding;

/*

*

每张小图之间的距离(横纵)dp

*/

private

int

mMargin

=

3;

private

ImageView[]

mGamePintuItems;

private

int

mItemWidth;

/*

*

游戏的图片

*/

private

Bitmap

mBitmap;

private

List<ImagePiece>

mItemBitmaps;

private

boolean

once;

/*

*

游戏面板的宽度

*/

private

int

mWidth;

private

boolean

isGameSuccess;

private

boolean

isGameOver;

public

interface

GamePintuListener

{

void

nextLevel(int

nextLevel);

void

timechanged(int

currentTime);

void

gameover();

}

public

GamePintuListener

mListener;

/*

*

设置接口回调

*/

public

void

setOnGamePintuListener(GamePintuListener

mListener)

{

this.mListener

=

mListener;

}

private

int

level

=

1;

private

static

final

int

TIME_CHANGED

=

0x110;

private

static

final

int

NEXT_LEVEL

=

0x111;

private

Handler

mHandler

=

new

Handler()

{

public

void

handleMessage(android.os.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--;

mHandler.sendEmptyMessageDelayed(TIME_CHANGED,

1000);

break;

case

NEXT_LEVEL:

level

=

level

+

1;

if

(mListener

!=

null)

{

mListener.nextLevel(level);

}

else

{

nextLevel();

}

break;

default:

break;

}

};

};

private

boolean

isTimeEnabled

=

false;

private

int

mTime;

/*

*

设置是否开启时间

*/

public

void

setTimeEnabled(boolean

isTimeEnabled)

{

this.isTimeEnabled

=

isTimeEnabled;

}

public

GamePintuLayout(Context

context)

{

this(context,

null);

}

public

GamePintuLayout(Context

context,

AttributeSet

attrs)

{

this(context,

attrs,

0);

}

public

GamePintuLayout(Context

context,

AttributeSet

attrs,

int

defStyle)

{

super(context,

attrs,

defStyle);

init();

}

private

void

init()

{

/*

*

单位的转换3--px

*/

mMargin

=

(int)

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

3,

getResources().getDisplayMetrics());

mPadding

=

min(getPaddingLeft(),

getPaddingRight(),

getPaddingTop(),

getPaddingBottom());

}

@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){

//根据当前等级设置时间

contTimeBaseLevel();

mHandler.sendEmptyMessage(TIME_CHANGED);

}

}

private

void

contTimeBaseLevel()

{

mTime

=

(int)Math.pow(2,

level)*60;

}

//

进行切图,以及排序

private

void

initBitmap()

{

//

TODO

Auto-generated

method

stub

if

(mBitmap

==

null)

{

mBitmap

=

BitmapFactory.decodeResource(getResources(),

R.drawable.image1);

}

mItemBitmaps

=

ImageSplitterUtil.splitImage(mBitmap,

mColumn);

//

使用sort完成我们的乱序

Collections.sort(mItemBitmaps,

new

Comparator<ImagePiece>()

{

public

int

compare(ImagePiece

a,

ImagePiece

b)

{

return

Math.random()

>

0.5

?

1

:

-1;

}

});

}

//

设置ImageView(Item)宽高等属性

private

void

initItem()

{

mItemWidth

=

(mWidth

-

mPadding

*

2

-

mMargin

*

(mColumn

-

1))

/

mColumn;

mGamePintuItems

=

new

ImageView[mColumn

*

mColumn];

//

生成Item,

设置Rule;

for

(int

i

=

0;

i

<

mGamePintuItems.length;

i++)

{

ImageView

item

=

new

ImageView(getContext());

item.setOnClickListener(this);

item.setImageBitmap(mItemBitmaps.get(i).getBitmap());

mGamePintuItems[i]

=

item;

item.setId(i

+

1);

//

item中tag存储了index

item.setTag(i

+

"_"

+

mItemBitmaps.get(i).getIndex());

RelativeLayout.LayoutParams

lp

=

new

RelativeLayout.LayoutParams(

mItemWidth,

mItemWidth);

//

设置item艰横向间隙,通过RightMargin

//

不是最后一列

if

((i

+

1)

%

mColumn

!=

0)

{

lp.rightMargin

=

mMargin;

}

//

不是第一列

if

(i

%

mColumn

!=

0)

{

lp.addRule(RelativeLayout.RIGHT_OF,

mGamePintuItems[i

-

1].getId());

}

//

如果不是第一行,设置TopMargin

and

rule

if

((i

+

1)

>

mColumn)

{

lp.topMargin

=

mMargin;

lp.addRule(RelativeLayout.BELOW,

mGamePintuItems[i

-

mColumn].getId());

}

addView(item,

lp);

}

}

public

void

restart()

{

isGameOver

=

false;

mColumn--;

nextLevel();

}

private

boolean

isPause;

public

void

pause()

{

isPause

=

true;

mHandler.removeMessages(TIME_CHANGED);

}

public

void

resume()

{

if(isPause)

{

isPause

=

false;

mHandler.sendEmptyMessage(TIME_CHANGED);

}

}

public

void

nextLevel()

{

this.removeAllViews();

mAnimLayout

=

null;

mColumn++;

isGameSuccess

=

false;

checkTimeEnable();

initBitmap();

initItem();

}

/*

*

获取多个参数的最小值

*/

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;

public

void

onClick(View

v)

{

if

(isAniming)

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;

//

交换我们的Item

exchangeView();

}

}

/*

*

动画层

*/

private

RelativeLayout

mAnimLayout;

private

boolean

isAniming;

/*

*

交换Item

*/

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

AnimationListener()

{

@Override

public

void

onAnimationStart(Animation

animation)

{

mFirst.setVisibility(View.INVISIBLE);

mSecond.setVisibility(View.INVISIBLE);

isAniming

=

true;

}

@Override

public

void

onAnimationRepeat(Animation

animation)

{

}

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

//

判断游戏用户是否成功

checkSuccess();

isAniming

=

false;

}

});

}

private

void

checkSuccess()

{

boolean

isSuccess

=

true;

for

(int

i

=

0;

i

<

mGamePintuItems.length;

i++)

{

ImageView

imageView

=

mGamePintuItems[i];

if

(getImageIndexByTag((String)

imageView.getTag())

!=

i)

{

isSuccess

=

false;

}

}

if

(isSuccess)

{

isGameSuccess

=

true;

mHandler.removeMessages(TIME_CHANGED);

Toast.makeText(getContext(),

"Success,

level

up!",

Toast.LENGTH_LONG).show();

mHandler.sendEmptyMessage(NEXT_LEVEL);

}

}

public

int

getImageIdByTag(String

tag)

{

String[]

split

=

tag.split("_");

return

Integer.parseInt(split[0]);

}

public

int

getImageIndexByTag(String

tag)

{

String[]

split

=

tag.split("_");

return

Integer.parseInt(split[1]);

}

/**

*

构造我们的动画层

*/

private

void

setUpAnimLayout()

{

if

(mAnimLayout

==

null)

{

mAnimLayout

=

new

RelativeLayout(getContext());

addView(mAnimLayout);

}

else

{

mAnimLayout.removeAllViews();

}

}

}MainActivity.javapackage

com.example.game_pintu;

import

android.app.Activity;

import

android.app.AlertDialog;

import

android.content.DialogInterface;

import

android.content.DialogInterface.OnClickListener;

import

android.os.Bundle;

import

android.widget.TextView;

import

com.example.game_pintu.view.GamePintuLayout;

import

com.example.game_pintu.view.GamePintuLayout.GamePintuListener;

public

class

MainActivity

extends

Activity

{

private

GamePintuLayout

mGamePintuLayout;

private

TextView

mLevel;

private

TextView

mTime;

@Override

protected

void

onCreate(Bundle

savedInstanceState)

{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTime

=

(TextView)

findViewById(R.id.id_time);

mLevel

=

(TextView)

findViewById(R.id.id_level);

mGamePintuLayout

=

(GamePintuLayout)

findViewById(R.id.id_gamepintu);

mGamePintuLayout.setTimeEnabled(true);

mGamePintuLayout.setOnGamePintuListener(new

GamePintuListener()

{

@Override

public

void

timechanged(int

currentTime)

{

mTime.setText(""

+

currentTime);

}

@Override

public

void

nextLevel(final

int

nextLevel)

{

new

AlertDialog.Builder(MainActivity.this)

.setTitle("GAME

INFO").setMessage("LEVEL

UP!!!")

.setPositiveButton("NEXT

LEVEL",

new

OnClickListener()

{

@Override

public

void

onClick(DialogInterface

dialog,

int

which)

{

mGamePintuLayout.nextLevel();

mLevel.setText(""

+

nextLevel);

}

}).show();

}

@Override

public

void

gameover()

{

new

AlertDialog.Builder(MainActivity.this)

.setTitle("GAME

INFO").setMessage("GAME

OVER!!!")

.setPositiveButton("RESTART",

new

OnClickListener()

{

@Override

public

void

onClick(DialogInterface

dialog,

int

which)

{

//

mGamePintuLayout.nextLevel();

mGamePintuLayout.restart();

}

}).setNegativeButton("QUIT",

new

OnClickListener()

{

@Override

public

void

onClick(DialogInterfac

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论