Android自定义View实现拼图小游戏
程序员文章站
2023-11-09 17:08:58
本文实例为大家分享了android拼图小游戏的具体代码,供大家参考,具体内容如下
1、效果图:
运行时:
结束时:
2、puzzlelayoutview:
p...
本文实例为大家分享了android拼图小游戏的具体代码,供大家参考,具体内容如下
1、效果图:
运行时:
结束时:
2、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);//添加到游戏面板中 } } }
工具类:imagesplitterutil
public 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; } }
实体类:imagepiecebean
public 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("是否放弃该游戏!", new dialoginterface.onclicklistener() { public void onclick(dialoginterface dialog, int which) { finish(); } }).show(); } }); } }
对应布局:activity_game
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp" android:gravity="center_horizontal" android:orientation="vertical"> <relativelayout android:layout_width="match_parent" android:layout_height="wrap_content"> <textview android:id="@+id/id_level" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="1" android:textsize="25sp" android:textstyle="bold" /> <textview android:id="@+id/id_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentright="true" android:gravity="center" android:text="120" android:textcolor="#ea7821" android:textsize="25sp" android:textstyle="bold" /> </relativelayout> <imageview android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginbottom="10dp" android:src="@drawable/pic_view" /> <com.helloworld.game.utils.puzzlelayoutview android:id="@+id/puzzle_layout_view" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="3dp" /> </linearlayout>
注意:pic_view图片资源自行更换
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。