版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在Android中通过自定义View实现一个拼图小游戏
怎么在Android中通过自定义View实现一个拼图小游戏?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。PuzzleLayoutView:public
class
PuzzleLayoutView
extends
RelativeLayout
implements
View.OnClickListener
{
//表示将其切成2*2拼图(默认4块)
private
int
mColumn
=
2;
//容器的内边距
private
int
mPadding;
//每个块块的边距(横,纵
3:表示间距为3dp)
private
int
mMargin
=
3;
//存储ImageView
private
ImageView[]
mGamePintuItems;
//Item的宽度(一致)
private
int
mItemWidth;
//游戏的图片
private
Bitmap
mBitmap;
//切图后的存储
private
List<ImagePieceBean>
mItemBitmaps;
//操作次数
private
boolean
once;
//容器宽度(游戏面板
高宽一致)
private
int
mWidth;
//设置游戏是否成功
private
boolean
isGameSuccess;
//设置游戏是否失败
private
boolean
isGameOver;
public
GamePintuListner
mListner;
public
PuzzleLayoutView(Context
context)
{
this(context,
null);
}
public
PuzzleLayoutView(Context
context,
AttributeSet
attrs)
{
this(context,
attrs,
0);
}
public
PuzzleLayoutView(Context
context,
AttributeSet
attrs,
int
defStyle)
{
super(context,
attrs,
defStyle);
init();
}
private
void
init()
{
mMargin
=
(int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
3,
getResources().getDisplayMetrics());//将dp转化为px,或xp转化为px
mPadding
=
min(getPaddingLeft(),
getPaddingRight(),
getPaddingTop(),
getPaddingBottom());
}
//接口方法
public
interface
GamePintuListner
{
void
nextLevel(int
nextLevel);//下一关
void
timechanged(int
currentTime);//关卡时间
void
gameover();//游戏结束
}
public
void
setOnGamePintuListner(GamePintuListner
mListner)
{
this.mListner
=
mListner;
}
private
int
level
=
1;
private
static
final
int
TIME_CHANGED
=
0X123;
private
static
final
int
NEXT_LEVEL
=
0X124;
private
Handler
handler
=
new
Handler()
{
public
void
handleMessage(android.os.Message
msg)
{
switch
(msg.what)
{
case
TIME_CHANGED:
if
(isGameSuccess
||
isGameOver)
return;
if
(mListner
!=
null)
{
mListner.timechanged(mTime);
//时间结束后,游戏结束
if
(mTime
==
0)
{
isGameOver
=
true;
mListner.gameover();
}
}
mTime--;
//延迟1秒发送
handler.sendEmptyMessageDelayed(TIME_CHANGED,
1000);
break;
case
NEXT_LEVEL:
level
=
level
+
1;//切换到下一关
if
(mListner
!=
null)
{
mListner.nextLevel(level);
}
else
{
nextLevel();
}
default:
break;
}
}
};
private
boolean
isTimeEnabled
=
false;
private
int
mTime;
/**
*
设置是否启动时间
(默认不启动)
*
*
@param
isTimeEnabled
*/
public
void
setTimeEnabled(boolean
isTimeEnabled)
{
this.isTimeEnabled
=
isTimeEnabled;
}
/**
*
获取当前布局的大小(正方形)
*/
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;//第一关120秒
第二关:240
第三关:480
}
/**
*
进行切图,以及排序方法
*/
private
void
initBitmap()
{
//将图片引入
if
(mBitmap
==
null)
{
mBitmap
=
BitmapFactory.decodeResource(getResources(),
R.drawable.pic_view);//注意此处的导包
}
mItemBitmaps
=
ImageSplitterUtil.sqlitImage(mBitmap,
mColumn);//返回长度为4
(2*2)
//使用sort进行乱排序
Collections.sort(mItemBitmaps,
new
Comparator<ImagePieceBean>()
{
public
int
compare(ImagePieceBean
a,
ImagePieceBean
b)
{//注意此处的a,b
//是否大于0.5具有不确定性
return
Math.random()
>
0.5
?
1
:
-1;
}
});
}
/**
*
设置ImageView(Item)的宽高等属性方法
*/
private
void
initItem()
{
//容器的宽度-Item内边距
=所有小块块加起来的/Item个数(宽度)
2:左边和右边边距
mItemWidth
=
(mWidth
-
mPadding
*
2
-
mMargin
*
(mColumn
-
1))
/
mColumn;
mGamePintuItems
=
new
ImageView[mColumn
*
mColumn];//界面块块个数相*
//生成我们的Item,设置Rule(Item间的关系,高矮等)
for
(int
i
=
0;
i
<
mGamePintuItems.length;
i++)
{
ImageView
item
=
new
ImageView(getContext());
/**
*
item点击事件
*/
item.setOnClickListener(this);
item.setImageBitmap(mItemBitmaps.get(i).getBitmap());//此前以进行过乱排序
mGamePintuItems[i]
=
item;//保存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和rule
if
(i
+
1
>
mColumn)
{
lp.topMargin
=
mMargin;
lp.addRule(RelativeLayout.BELOW,
mGamePintuItems[i
-
mColumn].getId());
}
addView(item,
lp);//添加到RelativeLayout中
}
}
/**
*
当过关失败,时间停止时调用此方法(重新开始此关卡)
*/
public
void
restart()
{
isGameOver
=
false;//重置当前关卡
mColumn--;
nextLevel();
}
public
void
nextLevel()
{
this.removeAllViews();//移除当前所有View
mAnimLayout
=
null;
mColumn++;//由2*2
变为3*3游戏面版
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;//点击的IItem
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("#5551c4d4"));//设置选中Item时的颜色(55为半透明)
}
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
animFirst
=
new
TranslateAnimation(0,
mSecond.getLeft()
-
mFirst.getLeft(),
0,
mSecond.getTop()
-
mFirst.getTop());
animFirst.setDuration(500);//设置动画时间
animFirst.setFillAfter(true);//设置动画结束的位置
first.startAnimation(animFirst);//启动动画
TranslateAnimation
animSecond
=
new
TranslateAnimation(0,
-mSecond.getLeft()
+
mFirst.getLeft(),
0,
-mSecond.getTop()
+
mFirst.getTop());
animSecond.setDuration(500);//设置动画时间
animSecond.setFillAfter(true);//设置动画结束的位置
second.startAnimation(animSecond);//启动动画
/**
*
监听动画事件
*/
animFirst.setAnimationListener(new
Animation.AnimationListener()
{
public
void
onAnimationStart(Animation
animation)
{
mFirst.setVisibility(View.INVISIBLE);//隐藏动画
mSecond.setVisibility(View.INVISIBLE);
isAniming
=
true;
}
public
void
onAnimationRepeat(Animation
animation)
{
}
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);
//此处为空,并不是将对象设置为null
而是将mFirst与Bitmap对象链接的线断开
mFirst
=
mSecond
=
null;//回到初始状态
mAnimLayout.removeAllViews();//移除动画层的两个View
//调用判断游戏成功时的方法
checkSuccess();
isAniming
=
false;
}
});
}
/**
*
判断游戏是否成功
*/
private
void
checkSuccess()
{
boolean
isSuccess
=
true;
for
(int
i
=
0;
i
<
mGamePintuItems.length;
i++)
{
ImageView
imageView
=
mGamePintuItems[i];
//getImageIndex:上面的方法名(注意此处方法名)
if
(getImageIndex((String)
imageView.getTag())
!=
i)
{
isSuccess
=
false;
}
}
if
(isSuccess)
{
isGameSuccess
=
true;
handler.removeMessages(TIME_CHANGED);//进入下一关时的时间
Log.e("TAG",
"SUCCESS");
Toast.makeText(getContext(),
"Success,level
up
游戏升级!!!",
Toast.LENGTH_LONG).show();
handler.sendEmptyMessage(NEXT_LEVEL);
}
}
/**
*
根据tag获取Id
*/
public
int
getImageIdByTag(String
tag)
{
String[]
split
=
tag.split("_");
return
Integer.parseInt(split[0]);//拿ID
}
public
int
getImageIndex(String
tag)
{
String[]
split
=
tag.split("_");
return
Integer.parseInt(split[1]);//拿ID
}
/**
*
构造我们的动画层
*/
private
void
setUpAnimLayout()
{
if
(mAnimLayout
==
null)
{
mAnimLayout
=
new
RelativeLayout(getContext());
addView(mAnimLayout);//添加到游戏面板中
}
}
}工具类:ImageSplitterUtilpublic
class
ImageSplitterUtil
{
/**
*
传入bitmap,切成piece*piece块
*/
public
static
List<ImagePieceBean>
sqlitImage(Bitmap
bitmap,
int
piece)
{
List<ImagePieceBean>
ImagePieceBeans
=
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++)
{//循环切第二,三行
ImagePieceBean
ImagePieceBean
=
new
ImagePieceBean();
ImagePieceBean.setIndex(j
+
i
*
piece);//第一次i为0,第0行
j++递增
0-6
int
x
=
j
*
pieceWidth;//第一次循环X,Y为0
int
y
=
i
*
pieceWidth;
ImagePieceBean.setBitmap(Bitmap.createBitmap(bitmap,
x,
y,
pieceWidth,
pieceWidth));
ImagePieceBeans.add(ImagePieceBean);
}
}
return
ImagePieceBeans;
}
}实体类:ImagePieceBeanpublic
class
ImagePieceBean
{
private
int
index;
//表示当前第几块
private
Bitmap
bitmap;
//当前图片
public
ImagePieceBean()
{
}
//快捷键构造方法
Source
倒3
public
ImagePieceBean(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
+
"]";
}
}3、使用方法:GameActivity/**
*
总结:
*
1.自定义控件选择,九宫格,RelativeLayout,
id+Rule
*
2.切图
*
3.动画图层
*
4.pause
resume
restart
*
5.游戏时间
Handler
sendMessageDelayed()
延迟一秒发送线程
*/
public
class
GameActivity
extends
AppCompatActivity
{
private
PuzzleLayoutView
puzzleLayoutView;
private
TextView
mLevel,
mTime;
protected
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_game);
mLevel
=
this.findViewById(R.id.id_level);
mTime
=
this.findViewById(R.id.id_time);
puzzleLayoutView
=
this.findViewById(R.id.puzzle_layout_view);
puzzleLayoutView.setTimeEnabled(true);
//监听事件
puzzleLayoutView.setOnGamePintuListner(new
PuzzleLayoutView.GamePintuListner()
{
public
void
timechanged(int
currentTime)
{
//此处为int
注意加""
mTime.setText(currentTime
+
"秒");
}
public
void
nextLevel(final
int
nextLevel)
{
//弹出提示框
new
AlertDialog.Builder(GameActivity.this).setTitle("游戏信息")
.setMessage("游戏升级").setPositiveButton("进入下一关",
new
DialogInterface.OnClickListener()
{
public
void
onClick(DialogInterface
dialog,
int
which)
{
//游戏结束后,调用下一关
puzzleLayoutView.nextLevel();
mLevel.setText("第"
+
+nextLevel
+
"关");
}
}).show();
}
public
void
gameover()
{
//弹出提示框
new
AlertDialog.Builder(GameActivity.this).setTitle("游戏信息")
.setMessage("游戏结束!").setPositiveButton("是否继续该关卡?",
new
DialogInterface.OnClickListener()
{
public
void
onClick(DialogInterface
dialog,
int
which)
{
puzzleLayoutView.restart();//重新启动
}
}).setNegativeButton("是否放弃该游戏!",
n
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年汽车维修工技能理论考试题库附答案(考试直接用)
- 2024女方婚内出轨离婚的协议书
- 2024年演出经纪人之演出经纪实务通关提分题库带答案(综合题)
- 2024年演出经纪人之演出经纪实务通关试题库及答案(夺冠系列)
- 2024年演出经纪人之演出经纪实务通关题库含答案(黄金题型)
- 2024年演出经纪人之演出经纪实务高分通关题型题库(达标题)
- 2024年演出经纪人之演出经纪实务高分题库(模拟题)
- 2024年苏教版六年级下册数学期末测试卷及完整答案【各地真题】
- 2024年苏教版六年级下册数学期末测试卷学生专用
- 2024年苏教版六年级下册数学期末测试卷附答案(达标题)
- GB/T 40742.1-2021产品几何技术规范(GPS)几何精度的检测与验证第1部分:基本概念和测量基础符号、术语、测量条件和程序
- GB/T 18885-2020生态纺织品技术要求
- 《广西优质天然矿泉水》(征求意见稿)编制说明
- 服务类验收单(模板)
- 圆锁小寿星讲话(5篇)
- FZ/T 73022-2019针织保暖内衣
- 工程项目培训制度9篇
- 第23课《太空一日》课件(共28张PPT) 部编版语文七年级下册
- 染色体数目变异课件
- 医院卫生院“以案促改”工作总结
- 工会基础工作操作实务(培训)课件
评论
0/150
提交评论