版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 第6课 植物养护基础知识 课件 2023-2024学年苏教版中劳动技术七年级下册
- 有关劳动合同
- 钢材销售合同5篇
- 2023年化妆品销售年终工作总结报告
- 2023年化学教育教学经验总结
- 垃圾焚烧炉相关行业投资方案
- 护栏清洗车相关行业投资方案范本
- 医用中心吸引系统行业相关投资计划提议范本
- 人教版二年级数学下册课件《用乘法口诀求商 第1课时》
- 在线供应链协同核算体系
- 空运集装板集装板
- 房屋赠与协议书电子模板(2篇)
- 项目部组建及项目实施管理办法
- 一年级劳动认识2-5种校园植物评课稿
- 主题亲子农场项目商业计划书
- 初中数学-变量之间的关系教学设计学情分析教材分析课后反思
- 学校关于开展保密法宣传周活动方案
- 维护政治安全工作情况报告
- 消化内镜操作、诊断及治疗
- 计算机网络教学能力大赛教学实施报告
- 07S906给水排水构筑物设计选用图化粪池
评论
0/150
提交评论