基于android平台的连连看系统_第1页
基于android平台的连连看系统_第2页
基于android平台的连连看系统_第3页
基于android平台的连连看系统_第4页
基于android平台的连连看系统_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

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

文档简介

1、android期末作业院 系:计算机与信息工程学院班 级:10级软件技术1班姓 名:学 号:完成日期:2013年1月5日基于android平台的连连看系统本系列文章记录只是为了增加android项目实战经验,将所学的知识用于相应的项目开发当中。首先介绍一下android中连连看项目的架构及所用到的技术进行简要分析,框架基本如下图所示: 本程序主要包含两大模块:即(1)表示层模块;(2)后台逻辑模块;其中表示层模块可以理解为游戏的ui及一些游戏辅助效果,表示层模块中,重要的是实现游戏的布局地图,项目中实现中,游戏的布局将使用自定义view的方式,在屏幕上贴图实现。而菜单模块及选关的dialog,

2、只是为用户提供一些常见的选择,如重玩,过关继续,音效开关等等,为了有一个更好的用户交互环境,dialog的实现将通过自定义dialog的方式。而游戏音效是mediaplayer在不同的状态场景下播放不同的游戏音效。而后台逻辑模块中,即时对于程序计算的实现与程序各种状态的监听,将是整个程序运行的基础。此模块中将实现对于游戏剩余时间限制和游戏状态的监听与处理。对于游戏剩余时间的监听,将开启单独的线程进行处理,从而不至于影响主程序逻辑的运行;游戏的状态的监控处理中,将会实现对于连通的两个图标的消除(即游戏界面的更新),游戏输赢的监听判断,游戏暂停与否等(暂停状态需要同时将剩余时间暂停,而时间监听线程

3、需要知道所处状态,此二者紧密联系)。对于本程序中最重要的还是程序中核心算法模块的实现,在游戏中,最主要的算法是判断两个选中的图标是否能够连通,其余两个算法也依赖于此算法而进行。下面着重介绍一下连接算法:在介绍连接算法之前,先简单介绍一下连连看的布局算法,为了简单起见,我们使用4*4的棋盘,假设棋子有四种:首先在程序初始化时,我们先将要加载的图片在棋盘上按序绘制出来,注意每一种图标我们绘制的时候需要一次性绘制两次,这样,才能保重绘制出来的每种图标的个数都是偶数个。假设最初如下图(1):图(1)最初绘制 图(2)调换后棋盘这样绘制后,我们进行一次遍历,随机的调换棋盘中的图标(是现有棋盘中的图标之间

4、的调换,并不是更改成为其他的图标)。经过调换的棋盘可能如图(2)所示这样就完成了棋盘的初始化,当然我们的棋盘在最外面一层中是不添加图标的,为的是我们连线时候能够使用最外层画线,而不会出现穿过图标画线的情况,棋盘如下图:在上一篇文章hellope的android项目实战之连连看设计篇中,我们进行了对android中连连看的项目的设计,包括功能模块的划分以及核心算法的设计。此文章接上文对android平台连连看程序进入实现阶段。在此项目中,根据上文中对于功能的分析,我们将实现以下类(下面即是工程的文件目录)在开发中,我们遵循由下向上的方式,也就是说,我们首先开发位于最底层的类,这种类并不依赖于其他

5、的我们需要实现的类。根据上文的分析,首先我们开发在表示层模块中的界面显示类,首先是boardview类,在android平台下,采用继承自view类的方式,看此类的代码,代码中尽量添加了详细的注释:package nate.llk.view;/*导入包种种再次略去*/public class boardview extends view protected static final int xcount = 10;protected static final int ycount = 12;map 连连看游戏棋盘,map中添加的int型在程序中的意思是index,而不是屏幕坐标!protect

6、ed int map = new intxcountycount;iconsize 图标大小,图标是正方形,所以一个int变量表示即可protected int iconsize;* iconcounts 图标的数目protected int iconcounts=19;* icons 所有的图片protected bitmap icons = new bitmapiconcounts;* path 可以连通点的路径private point path = null;* selected 选中的图标protected list selected = new arraylist();* para

7、m context* param attrspublic boardview(context context, attributeset attrs) super(context, attrs);caliconsize();resources r = getresources();/载入连连看中的图标资源loadbitmaps(1, r.getdrawable(r.drawable.fruit_01);loadbitmaps(2, r.getdrawable(r.drawable.fruit_02);loadbitmaps(3, r.getdrawable(r.drawable.fruit_0

8、3);loadbitmaps(4, r.getdrawable(r.drawable.fruit_04);loadbitmaps(5, r.getdrawable(r.drawable.fruit_05);loadbitmaps(6, r.getdrawable(r.drawable.fruit_06);loadbitmaps(7, r.getdrawable(r.drawable.fruit_07);loadbitmaps(8, r.getdrawable(r.drawable.fruit_08);loadbitmaps(9, r.getdrawable(r.drawable.fruit_0

9、9);loadbitmaps(10, r.getdrawable(r.drawable.fruit_10);loadbitmaps(11, r.getdrawable(r.drawable.fruit_11);loadbitmaps(12, r.getdrawable(r.drawable.fruit_12);loadbitmaps(13, r.getdrawable(r.drawable.fruit_13);loadbitmaps(14, r.getdrawable(r.drawable.fruit_14);loadbitmaps(15, r.getdrawable(r.drawable.f

10、ruit_15);loadbitmaps(16, r.getdrawable(r.drawable.fruit_17);loadbitmaps(17, r.getdrawable(r.drawable.fruit_18);loadbitmaps(18, r.getdrawable(r.drawable.fruit_19);private void caliconsize()/取得屏幕的大小displaymetrics dm = new displaymetrics();(activity) this.getcontext().getwindowmanager().getdefaultdispl

11、ay().getmetrics(dm);iconsize = dm.widthpixels/( xcount );* 函数目的在于载入图标资源,同时将一个key(特定的整数标识)与一个图标进行绑定* param key 特定图标的标识* param d drawable下的资源public void loadbitmaps(int key,drawable d)bitmap bitmap = bitmap.createbitmap(iconsize,iconsize,bitmap.config.argb_8888);canvas canvas = new canvas(bitmap);d.se

12、tbounds(0, 0, iconsize, iconsize);d.draw(canvas);iconskey=bitmap; /未用0 号index* view自带的,但是在此方法中,有画路径(删除联通的两个图标),* 绘制棋盘的所有图标(也可理解为刷新,只要此map位置值0)* 放大第一个选中的图标(selected.size() = 1)overrideprotected void ondraw(canvas canvas) if(path != null & path.length = 2)for(int i = 0; i path.length - 1;+i)paint pain

13、t = new paint();paint.setcolor(color.blue);paint.setstrokewidth(3);paint.setstyle(paint.style.stroke);point p1 = indextoscreen(pathi.x,pathi.y);point p2 = indextoscreen(pathi + 1.x,pathi + 1.y);canvas.drawline(p1.x + iconsize/2, p1.y + iconsize/2, p2.x + iconsize/2, p2.y + iconsize/2, paint);mappath

14、0.xpath0.y = 0;mappathpath.length - 1.xpathpath.length -1.y = 0;selected.clear(); path = null;* 绘制棋盘的所有图标 当这个坐标内的值大于0时绘制for(int x = 1;x xcount - 1; +x)for(int y = 1; y 0)point p = indextoscreen(x, y);canvas.drawbitmap(iconsmapxy, p.x,p.y,null);* 绘制选中图标,当选中时图标放大显示/for(point position:selected)if(selec

15、ted.size() 0)point position = selected.get(0);point p = indextoscreen(position.x, position.y);if(mapposition.xposition.y = 1)canvas.drawbitmap(iconsmapposition.xposition.y,null,new rect(p.x-5, p.y-5, p.x + iconsize + 5, p.y + iconsize + 5), null);super.ondraw(canvas);* param x 数组中的横坐标* param y 数组中的纵

16、坐标* return 将图标在数组中的坐标转成在屏幕上的真实坐标public point indextoscreen(int x,int y)return new point(x * iconsize,y * iconsize);* param x 屏幕中的横坐标* param y 屏幕中的纵坐标* return 将图标在屏幕中的坐标转成在数组上的虚拟坐标public point screentoindex(int x,int y)int xindex = x / iconsize;int yindex = y / iconsize;if(xindex xcount & yindex 0 &

17、!isstop)timerlistener.ontimer(lefttime);lefttime -;try thread.sleep(1000); catch (interruptedexception e) e.printstacktrace();if(isstop & lefttime 0)if(win();/setmode(win);elsesetmode(pause);/setmode(lose);else if(lefttime = 0)setmode(lose);public void stoptimer()isstop = true;iscontinue = false;pub

18、lic void setcontinue()iscontinue = true;isstop = false;refreshtime = new refreshtime();thread t = new thread(refreshtime); /注意正确启动一个实现runnable接口的线程t.start();上面已经提过,此线程用于控制游戏的时间。在此,再介绍自定义的几个接口,public interface onstatelistenerpublic void onstatechanged(int statemode);只含有一个方法,主要对于游戏状态的变换的监听,比如pause,sto

19、p等等。public interface ontimerlistenerpublic void ontimer(int lefttime);用于监听剩余时间,与上面线程不同的是,此方法中利用上面线程的lefttime的结果,主要用于更新游戏中用于提醒玩家的时间进度条。public interface ontoolschangelistenerpublic void onrefreshchanged(int count);public void ontipchanged(int count);tool即是我们的游戏中提供给玩家的两个工具,一个是refresh一下游戏界面,即将现有的棋盘重新打乱(

20、当然,现有图表数量不变),另一个是之前提过的hint的自动帮助功能,帮助玩家找到一组能够连通的图标。当然,这两种工具都有次数的限制。文接上回,之前介绍了项目的架构,进行了功能的分析,同时进行了boardview类及时间控制类的开发及几个几口的介绍。这次我们将完整的实现游戏棋盘的绘制与touch事件的处理,以及游戏核心算法中连接算法、hint自动帮助算法与判断是否无解算法的实现。这些代码的处理都在继承自boardview类的gameview类中。首先在gameview类中添加实现本游戏主要算法的代码,即连接算法的代码(用于判断给定的两个位置的图标能够相连通): * 本游戏的核心算法,判断两个连接

21、点是否能够连接,这里传进来的就是我们点击的两个点转化成index的值list p1expand = new arraylist();list p2expand = new arraylist();public boolean link(point p1,point p2)if(p1.equals(p2)return false;path.clear();if(mapp1.xp1.y = mapp2.xp2.y)if(linkdirect(p1,p2)path.add(p1);path.add(p2);return true;* 一个拐点的判断point px = new point(p1.x,

22、p2.y); /假设第一种可能点if(mapp1.xp2.y = 0 & linkdirect(p1,px) & linkdirect(px,p2)path.add(p1);path.add(px);path.add(p2);return true;point py = new point(p2.x,p1.y); /假设第二种可能点if(mapp2.xp1.y = 0 & linkdirect(p1,py) & linkdirect(py,p2)/首先判断mapp2.xp1.y中介点是否有图标path.add(p1);path.add(py);path.add(p2);return true;

23、* 两个折点(corner)expandx(p1,p1expand);expandx(p2,p2expand);for(int i = 0; i p1expand.size(); i+)for(int j = 0; j p2expand.size(); j+)if(p1expand.get(i).x = p2expand.get(j).x)if(linkdirect(p1expand.get(i),p2expand.get(j)path.add(p1);path.add(p1expand.get(i);path.add(p2expand.get(j);path.add(p2);return t

24、rue;expandy(p1,p1expand);expandy(p2,p2expand);for(point exp1:p1expand)for(point exp2:p2expand)if(exp1.y = exp2.y)if(linkdirect(exp1,exp2)path.add(p1);path.add(exp1);path.add(exp2);path.add(p2);return true;return false; /最后三种方式都不能连通,还是要return false ,不然在两个同样的图标下却没有返回值!return false;* 判断直线链接,无拐角,传进来的点值是

25、screentoindex过的了,不过这里传进来的不一定就是我们点击的点,也可能是我们的拐角点(辅助点)* param p1* param p2public boolean linkdirect(point p1,point p2)/if(mapp1.xp1.y = mapp2.xp2.y)/纵向直线if(p1.x = p2.x)int y1 = math.min(p1.y, p2.y);int y2 = math.max(p1.y, p2.y);boolean flag = true;for(int y = y1 + 1; y y2; y+)/这个循环里容易漏掉两个相邻的情况,所以才加上上面

26、的flag样式if(mapp1.xy != 0)flag = false;break;if(flag)return true;/横直线判断if(p1.y = p2.y)int x1 = math.min(p1.x, p2.x);int x2 = math.max(p1.x, p2.x);boolean flag = true;for(int x = x1 + 1; x x2; x+)if(mapxp1.y != 0)flag = false;break;if(flag)return true;return false;public void expandx(point p,list list)

27、list.clear();for(int x = p.x + 1; x = 0; x-)if(mapxp.y != 0)break;list.add(new point(x,p.y);* 向y方向扩展,传进来的点是index过的,而list是作为“返回值”需要保存的值public void expandy(point p,list list)list.clear();for(int y = p.y + 1; y = 0; y-)if(mapp.xy != 0)break;list.add(new point(p.x,y);代码中尽量添加注释,此段代码中实现了第一篇文章中进行的算法分析,其中li

28、nk(point p1,point p2)函数作为算法真正的完整实现者,算法的主逻辑有它实现,linkdirect(point p1,point p2)函数作为一个工具函数,用于判断给定的两个位置(注意不是两个图标,因为给定的位置不一定含有图标,当我们在判断”一折型“和“二折型”的情况的时候即使如此)。而expandx(point p,list list)与 expandy(point p,list list)两个方法的同样作为工具函数,在判断“二折型”情况时候将会使用,也就是前面所说的“横向扫描”与“纵横扫描”。而对于link(point p1,point p2)函数中,我们的逻辑还是将大问

29、题化为小问题处理。最终还是分解到调用linkdirect(point p1,point p2)函数来进行“直线型”的处理。以上即是程序的连接算法的实现,除了程序算法逻辑的理解之外,还需注意在判断的时候,若能够连通,我们已经将private list path = new arraylist();保存连通路径的path附上值,记得当link函数返回true时,path中即保存了一条相通的路径!完成了连接算法,下一步我们将依赖于连接算法的实现,完成扫描是否当前地图已经出现无解的情况,因为程序的地图是随机生成的,难免有时候会出现无解的情况;下面我们将实现判断是否处于无解状态,实现函数:*用于判断是否

30、当前已经无解 public boolean die()for(int y= 1; y ycount; y+) /表示从此行中的一个元素开始扫描(起点)for(int x = 1; x xcount; x+) /表示此行中指定列,组成扫描起点if(mapxy != 0) for(int j = y; j ycount; j+)/表示正在被扫描的行if(j = y)/循环中的第一次扫描,为什么特殊?因为此时不一定从一行中的第一个元素开始扫描for(int i = x + 1; i xcount - 1; i+)if(mapxy = mapij & link(new point(x,y),new p

31、oint(i,j)return false;elsefor(int i = 1; i xcount -1; i+)if(mapxy = mapij & link(new point(x,y),new point(i,j)return false;return true;代码中也有相应注释,每一次判断相当于一次遍历棋盘,同时注意,如果die()函数返回为false,这则证明link()函数返回了true!前面已经提醒过:当link返回true时,我们用于保存连通路径的path对象中已经保存了一条连通路径的点的集合,只不过在die()函数中运行得到的是按遍历顺序而来的,并不是我们所指定的两个始点与

32、终点两个图标;所以在这儿,可以借die()的判断,完成我们算法实现的第三个功能,即hint的自动帮助?* 当点击help按钮时候调用,会帮助玩家消除一对图标public void autohelp()if(help = 0)/soundplay.play(id_sound_error, 0);return ;else/soundplay.play(id_sound_tip, 0);help-;toolschangedlistener.ontipchanged(help);drawline(path.toarray(new point );refreshhandler.sendrefresh(5

33、00);当然此处需要介绍一下最后一行代码的来历:class refreshhandler extends handleroverridepublic void handlemessage(message msg) super.handlemessage(msg);if(msg.what = refresh_view)gameview.this.invalidate();if(win()setmode(win);isstop = true;iscontinue = false;else if(die() /调用一次die方法!此时如果die返回为false,即还能够连通change(); pub

34、lic void sendrefresh(int delaytime)message msg = new message();this.removemessages(0);msg.what = refresh_view;this.sendmessagedelayed(msg, delaytime);当然对于是否已经为赢了的判断win()函数比较简单,就是扫描棋盘,如果所有位置map值都为了0,即赢了,若不是,还未完成;这里就不贴代码了。gameview类中还有一个职能就是初始化一张棋盘:我们初始化棋盘时,利用前面讲解的初始算法技术,遍历棋盘,先将棋盘填满,但是填满首先还有一个规则就是每一种图标

35、的填入必须同时填入两张,是为每种图标都为偶数个而设定!介绍一下最后调用的change()函数,也是出自于第一篇的棋盘初始算法,用于随机将棋盘中的图标打乱:随机将现有的布局打乱,重新布局,map中现有图标数量不变,相当于一次refreshpublic void change()random random = new random();int tmp,xtmp,ytmp;for(int x = 1;x xcount -1; x+)for(int y = 1; y ycount -1; y+)xtmp = 1 + random.nextint(xcount -2);ytmp = 1 + random

36、.nextint(ycount - 2);tmp = mapxy;mapxy = mapxtmpytmp;mapxtmpytmp = tmp;if(die() /如出现无解情况,即需要再次随机重新打乱change();gameview类还是一个view,在此类中我们还要重写view的ontouchevent方法:* 对于选择的处理,如果是第一次按下,则将其加入到selected当中,* 若是第二次(selected.size()=1),则先判断能不能连通overridepublic boolean ontouchevent(motionevent event) int sx = (int)event.getx();int sy = (int)event.gety();point p = screentoindex(sx, sy);if(mapp.xp.y != 0)if(selected.size() = 1)if(link(selected.

温馨提示

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

最新文档

评论

0/150

提交评论