Android中贪吃蛇游戏的学习(三)
16lz
2021-12-04
Android中贪吃蛇游戏的学习(三)
文章分类:移动开发
视图VIew的类的Snake的,主要关注的学习的类。
Java代码- packagecom.easyway.dev.android.snake;
- importjava.util.ArrayList;
- importjava.util.Random;
- importandroid.content.Context;
- importandroid.content.res.Resources;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.util.AttributeSet;
- importandroid.util.Log;
- importandroid.view.KeyEvent;
- importandroid.view.View;
- importandroid.widget.TextView;
- /**
- *View类是Android的一个超类,这个类几乎包含了所有的屏幕类型。但它们之间有一些不同。每一个view
- *都有一个用于绘画的画布。这个画布可以用来进行任意扩展。
- *
- *一个项目的R.java文件是一个定义所有资源的索引文件。使用这个类就像使用一种速记方式来引用你项
- *目中包含的资源。这个有点特别的强大像对于Eclipse这类IDE的代码编译特性,因为它使你快速的,互动
- *式的定位你正在寻找的特定引用。
- *
- *到目前需要注意的重要事情是叫做”layout”的内部类和他的成员变量”main”,插件会通知你添加一个新
- *的XML布局文件,然后从新产生这个R.java文件,比如你添加了新的资源到你的项目,你将会看到R.java
- *也相应的改变了。放在你的项目目录的res/文件夹下。“res”是”resources”的缩写,它是存放所有非
- *代码资源的文件夹,包含象图片,本地化字符串和XML布局文件。
- *
- *
- *SnakeView:implementationofasimplegameofSnake
- *创建的view中一般要传入一个Context的实例,Context可以控制系统的调用,它提供了诸如资源解析
- *,访问数据库等。Activty类继承自Context类。
- *
- *视图也可以被嵌套,但和J2ME不同,我们可以将定制的视图和Android团队发布的Widgets一起使用。
- *在J2ME中,开发人员被迫选择GameCanvas和J2ME应用程序画布。这就意味着如果我们想要一个定制
- *的效果,就必须在GameCanvas上重新设计我们所有的widget。Android还不仅仅是这些,视图类型
- *也可以混合使用。Android还带了一个widget库,这个类库包括了滚动条,文本实体,进度条以及其
- *他很多控件。这些标准的widget可以被重载或被按着我们的习惯定制。
- *
- */
- publicclassSnakeViewextendsTileView{
- privatestaticfinalStringTAG="SnakeView";
- /**
- *Currentmodeofapplication:READYtorun,RUNNING,oryouhavealready
- *lost.staticfinalintsareusedinsteadofanenumforperformance
- *reasons.
- */
- privateintmMode=READY;
- publicstaticfinalintPAUSE=0;
- publicstaticfinalintREADY=1;
- publicstaticfinalintRUNNING=2;
- publicstaticfinalintLOSE=3;
- /**
- *设置方向
- *Currentdirectionthesnakeisheaded.
- */
- privateintmDirection=NORTH;
- privateintmNextDirection=NORTH;
- privatestaticfinalintNORTH=1;
- privatestaticfinalintSOUTH=2;
- privatestaticfinalintEAST=3;
- privatestaticfinalintWEST=4;
- /**
- *LabelsforthedrawablesthatwillbeloadedintotheTileViewclass
- */
- privatestaticfinalintRED_STAR=1;
- privatestaticfinalintYELLOW_STAR=2;
- privatestaticfinalintGREEN_STAR=3;
- /**
- *mScore:usedtotrackthenumberofapplescapturedmMoveDelay:numberof
- *millisecondsbetweensnakemovements.Thiswilldecreaseasapplesare
- *captured.
- */
- privatelongmScore=0;
- privatelongmMoveDelay=600;
- /**
- *mLastMove:trackstheabsolutetimewhenthesnakelastmoved,andisused
- *todetermineifamoveshouldbemadebasedonmMoveDelay.
- */
- privatelongmLastMove;
- /**
- *mStatusText:textshowstotheuserinsomerunstates
- */
- privateTextViewmStatusText;
- /**
- *用于存储贪吃蛇中,苹果和蛇的点阵的坐标的信息的集合
- *mSnakeTrail:alistofCoordinatesthatmakeupthesnake'sbody
- *mAppleList:thesecretlocationofthejuicyapplesthesnakecraves.
- */
- privateArrayList<Coordinate>mSnakeTrail=newArrayList<Coordinate>();
- privateArrayList<Coordinate>mAppleList=newArrayList<Coordinate>();
- /**
- *为创建苹果坐标使用随机对象
- *Everyoneneedsalittlerandomnessintheirlife
- */
- privatestaticfinalRandomRNG=newRandom();
- /**
- *刷新界面处理器
- *Createasimplehandlerthatwecanusetocauseanimationtohappen.We
- *setourselvesasatargetandwecanusethesleep()
- *functiontocauseanupdate/invalidatetooccuratalaterdate.
- */
- privateRefreshHandlermRedrawHandler=newRefreshHandler();
- /**
- *实现刷新的功能:
- *在J2ME中,刷新都是在canvas中通过调用线程结合repaint()来刷新,他们使线程不断去循环,
- *去调用canvas,笔者在android入门时也曾经想用J2ME的模式用在android中,结果报异常了,
- *为什么呢?很多人认为Dalvik虚拟机是一个Java虚拟机,因为Android的编程语言恰恰就是Java语言。
- *但是这种说法并不准确,因为Dalvik虚拟机并不是按照Java虚拟机的规范来实现的,两者并不兼容;
- *同时还要两个明显的不同:Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的
- *文件格式DEX(DalvikExecutable)。所以在以前JAVA里面能使用的模式,可能在android
- *里面用不起来。在自带的例子里面他是通过消息的机制来刷新的。而在android的消定义比较广泛,
- *比如,手机的暂停,启动,来电话、短信,键盘按下,弹起都是一个消息。总的来说,事件就是消息;
- *只要继承Handler类就可以对消息进行控制,或者处理,根据具体情况进行具体处理:
- *
- *@authorAdministrator
- *@date2010-5-24
- *@version1.0
- *@sinceJDK6.0
- */
- classRefreshHandlerextendsHandler{
- /**
- *响应消息
- */
- @Override
- publicvoidhandleMessage(Messagemsg){
- SnakeView.this.update();
- SnakeView.this.invalidate();
- }
- /**
- *向外提供人工的调用消息的接口
- *@paramdelayMillis
- */
- publicvoidsleep(longdelayMillis){
- //注销消息
- this.removeMessages(0);
- //添加消息
- sendMessageDelayed(obtainMessage(0),delayMillis);
- }
- };
- /**
- *ConstructsaSnakeViewbasedoninflationfromXML
- *
- *@paramcontext
- *@paramattrs
- */
- publicSnakeView(Contextcontext,AttributeSetattrs){
- super(context,attrs);
- initSnakeView();
- }
- publicSnakeView(Contextcontext,AttributeSetattrs,intdefStyle){
- super(context,attrs,defStyle);
- initSnakeView();
- }
- /**
- *初始化界面的
- */
- privatevoidinitSnakeView(){
- setFocusable(true);
- Resourcesr=this.getContext().getResources();
- resetTiles(4);
- loadTile(RED_STAR,r.getDrawable(R.drawable.redstar));
- loadTile(YELLOW_STAR,r.getDrawable(R.drawable.yellowstar));
- loadTile(GREEN_STAR,r.getDrawable(R.drawable.greenstar));
- }
- /**
- *初始化新的游戏
- */
- privatevoidinitNewGame(){
- mSnakeTrail.clear();
- mAppleList.clear();
- //Fornowwe'rejustgoingtoloadupashortdefaulteastboundsnake
- //that'sjustturnednorth
- //设置初始化蛇的位置
- mSnakeTrail.add(newCoordinate(7,7));
- mSnakeTrail.add(newCoordinate(6,7));
- mSnakeTrail.add(newCoordinate(5,7));
- mSnakeTrail.add(newCoordinate(4,7));
- mSnakeTrail.add(newCoordinate(3,7));
- mSnakeTrail.add(newCoordinate(2,7));
- mNextDirection=NORTH;
- //Twoapplestostartwith
- //设置苹果的位置
- addRandomApple();
- addRandomApple();
- //
- mMoveDelay=600;
- //设置积分的
- mScore=0;
- }
- /**
- *GivenaArrayListofcoordinates,weneedtoflattenthemintoanarrayof
- *intsbeforewecanstuffthemintoamapforflatteningandstorage.
- *
- *@paramcvec:aArrayListofCoordinateobjects
- *@return:asimplearraycontainingthex/yvaluesofthecoordinates
- *as[x1,y1,x2,y2,x3,y3...]
- */
- privateint[]coordArrayListToArray(ArrayList<Coordinate>cvec){
- intcount=cvec.size();
- int[]rawArray=newint[count*2];
- for(intindex=0;index<count;index++){
- Coordinatec=cvec.get(index);
- rawArray[2*index]=c.x;
- rawArray[2*index+1]=c.y;
- }
- returnrawArray;
- }
- /**
- *Savegamestatesothattheuserdoesnotloseanything
- *ifthegameprocessiskilledwhileweareinthe
- *background.
- *
- *@returnaBundlewiththisview'sstate
- */
- publicBundlesaveState(){
- Bundlemap=newBundle();
- map.putIntArray("mAppleList",coordArrayListToArray(mAppleList));
- map.putInt("mDirection",Integer.valueOf(mDirection));
- map.putInt("mNextDirection",Integer.valueOf(mNextDirection));
- map.putLong("mMoveDelay",Long.valueOf(mMoveDelay));
- map.putLong("mScore",Long.valueOf(mScore));
- map.putIntArray("mSnakeTrail",coordArrayListToArray(mSnakeTrail));
- returnmap;
- }
- /**
- *Givenaflattenedarrayofordinatepairs,wereconstitutethemintoa
- *ArrayListofCoordinateobjects
- *
- *@paramrawArray:[x1,y1,x2,y2,...]
- *@returnaArrayListofCoordinates
- */
- privateArrayList<Coordinate>coordArrayToArrayList(int[]rawArray){
- ArrayList<Coordinate>coordArrayList=newArrayList<Coordinate>();
- intcoordCount=rawArray.length;
- for(intindex=0;index<coordCount;index+=2){
- Coordinatec=newCoordinate(rawArray[index],rawArray[index+1]);
- coordArrayList.add(c);
- }
- returncoordArrayList;
- }
- /**
- *Restoregamestateifourprocessisbeingrelaunched
- *
- *@paramicicleaBundlecontainingthegamestate
- */
- publicvoidrestoreState(Bundleicicle){
- setMode(PAUSE);
- //从资源中获取ArrayList
- mAppleList=coordArrayToArrayList(icicle.getIntArray("mAppleList"));
- mDirection=icicle.getInt("mDirection");
- mNextDirection=icicle.getInt("mNextDirection");
- mMoveDelay=icicle.getLong("mMoveDelay");
- mScore=icicle.getLong("mScore");
- mSnakeTrail=coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));
- }
- /**
- *重点的控制代码
- *
- *实现键盘事件:键盘主要起操作作用,在任何的手机游戏中键盘都是起重要的用,要本游戏中,
- *他就是起控制蛇的行走方向:现在我们分析他的代码:
- *就是通过判断那个键按下,然后再给要走的方向(mDirection)赋值。
- *
- *handleskeyeventsinthegame.Updatethedirectionoursnakeistraveling
- *basedontheDPAD.Ignoreeventsthatwouldcausethesnaketoimmediately
- *turnbackonitself.
- *
- *(non-Javadoc)
- *
- *@seeandroid.view.View#onKeyDown(int,android.os.KeyEvent)
- */
- @Override
- publicbooleanonKeyDown(intkeyCode,KeyEventmsg){
- if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
- if(mMode==READY|mMode==LOSE){
- /*
- *Atthebeginningofthegame,ortheendofapreviousone,
- *weshouldstartanewgame.
- */
- initNewGame();
- setMode(RUNNING);
- update();
- return(true);
- }
- if(mMode==PAUSE){
- /*
- *Ifthegameismerelypaused,weshouldjustcontinuewhere
- *weleftoff.
- */
- setMode(RUNNING);
- update();
- return(true);
- }
- if(mDirection!=SOUTH){
- mNextDirection=NORTH;
- }
- return(true);
- }
- if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
- if(mDirection!=NORTH){
- mNextDirection=SOUTH;
- }
- return(true);
- }
- if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT){
- if(mDirection!=EAST){
- mNextDirection=WEST;
- }
- return(true);
- }
- if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT){
- if(mDirection!=WEST){
- mNextDirection=EAST;
- }
- return(true);
- }
- returnsuper.onKeyDown(keyCode,msg);
- }
- /**
- *SetstheTextViewthatwillbeusedtogiveinformation(suchas"Game
- *Over"totheuser.
- *
- *@paramnewView
- */
- publicvoidsetTextView(TextViewnewView){
- mStatusText=newView;
- }
- /**
- *Updatesthecurrentmodeoftheapplication(RUNNINGorPAUSEDorthelike)
- *aswellassetsthevisibilityoftextviewfornotification
- *
- *@paramnewMode
- */
- publicvoidsetMode(intnewMode){
- intoldMode=mMode;
- mMode=newMode;
- if(newMode==RUNNING&oldMode!=RUNNING){
- mStatusText.setVisibility(View.INVISIBLE);
- update();
- return;
- }
- Resourcesres=getContext().getResources();
- CharSequencestr="";
- if(newMode==PAUSE){
- str=res.getText(R.string.mode_pause);
- }
- if(newMode==READY){
- str=res.getText(R.string.mode_ready);
- }
- if(newMode==LOSE){
- str=res.getString(R.string.mode_lose_prefix)+mScore
- +res.getString(R.string.mode_lose_suffix);
- }
- mStatusText.setText(str);
- mStatusText.setVisibility(View.VISIBLE);
- }
- /**
- *
- *生成苹果位置的代码:
- *苹果的位置就是更简单了,他是随机生成的,而且必须在现在蛇的位置相对远距离。
- *
- *Selectsarandomlocationwithinthegardenthatisnotcurrentlycovered
- *bythesnake.Currently_could_gointoaninfiniteloopifthesnake
- *currentlyfillsthegarden,butwe'llleavediscoveryofthisprizetoa
- *trulyexcellentsnake-player.
- *
- */
- privatevoidaddRandomApple(){
- CoordinatenewCoord=null;
- booleanfound=false;
- while(!found){
- //随机生成新的X,Y位置
- //Chooseanewlocationforourapple
- intnewX=1+RNG.nextInt(mXTileCount-2);
- intnewY=1+RNG.nextInt(mYTileCount-2);
- newCoord=newCoordinate(newX,newY);
- //Makesureit'snotalreadyunderthesnake
- booleancollision=false;
- intsnakelength=mSnakeTrail.size();
- for(intindex=0;index<snakelength;index++){
- //检查一下存放的位置是否合理
- if(mSnakeTrail.get(index).equals(newCoord)){
- collision=true;
- }
- }
- //ifwe'rehereandthere'sbeennocollision,thenwehave
- //agoodlocationforanapple.Otherwise,we'llcircleback
- //andtryagain
- found=!collision;
- }
- if(newCoord==null){
- Log.e(TAG,"SomehowendedupwithanullnewCoord!");
- }
- //添加苹果的列表中的
- mAppleList.add(newCoord);
- }
- /**
- *Handlesthebasicupdateloop,checkingtoseeifweareintherunning
- *state,determiningifamoveshouldbemade,updatingthesnake'slocation.
- */
- publicvoidupdate(){
- if(mMode==RUNNING){
- longnow=System.currentTimeMillis();
- if(now-mLastMove>mMoveDelay){
- clearTiles();
- updateWalls();
- updateSnake();
- updateApples();
- mLastMove=now;
- }
- mRedrawHandler.sleep(mMoveDelay);
- }
- }
- /**
- *调用以上的方法以循环的方式位置数组赋值以及图片的索引。
- *
- *Drawssomewalls.
- *
- */
- privatevoidupdateWalls(){
- for(intx=0;x<mXTileCount;x++){
- setTile(GREEN_STAR,x,0);//设置顶部的界限的位置
- setTile(GREEN_STAR,x,mYTileCount-1);//设置底部界限的位置
- }
- for(inty=1;y<mYTileCount-1;y++){
- setTile(GREEN_STAR,0,y);//设置顶部的界限的位置
- setTile(GREEN_STAR,mXTileCount-1,y);//设置底部界限的位置
- }
- }
- /**
- *Drawssomeapples.
- *
- */
- privatevoidupdateApples(){
- for(Coordinatec:mAppleList){
- setTile(YELLOW_STAR,c.x,c.y);
- }
- }
- /**
- *设置当前蛇的方向位置:
- *从以上的键盘代码我们可以看得出,程序中是通过触发来改变坐标(+1,-1)的方式来改蛇头的方向,
- *可见坐标在游戏编程中的作用,这个也是根据手机的屏幕是点阵的方式来显示,所以坐标就是一个
- *定位器。在这里大家可能还有一个疑问。就是就这个蛇什么能够以“7”字形来移动行走,其实我们
- *稍微仔细观察一下就知道了,在这里面,他们也是通过坐标的传递来实现的,只要把头部的坐标点
- *依次赋给下一个点,后面的每一个点都走过了头部所走过的点,而蛇的头部就是负责去获取坐标,整
- *个蛇的行走起来就很自然和连贯。坐标的方向变换又是通过判断那个方向按键的按下来改变的,这
- *样一来,键盘的作用就发挥出来了。蛇吃苹果又是怎样去实现?上面我所说到的坐标就起了作用。在蛇
- *所经过的每一个坐标,他们都要在苹果所在的(ArrayList<Coordinate>mAppleList=new
- *ArrayList<Coordinate>())坐标集里面集依次判断,若是坐标相同,那个这个苹果就被蛇吃了。
- *
- *Figureoutwhichwaythesnakeisgoing,seeifhe'srunintoanything(the
- *walls,himself,oranapple).Ifhe'snotgoingtodie,wethenaddtothe
- *frontandsubtractfromtherearinordertosimulatemotion.Ifwewantto
- *growhim,wedon'tsubtractfromtherear.
- *
- */
- privatevoidupdateSnake(){
- booleangrowSnake=false;
- //grabthesnakebythehead
- //获取蛇的头部
- Coordinatehead=mSnakeTrail.get(0);
- //创建一个新的蛇的头部应该的位置
- CoordinatenewHead=newCoordinate(1,1);
- //根据当前的为方向设置坐标的信息
- mDirection=mNextDirection;
- switch(mDirection){
- caseEAST:{
- newHead=newCoordinate(head.x+1,head.y);
- break;
- }
- caseWEST:{
- newHead=newCoordinate(head.x-1,head.y);
- break;
- }
- caseNORTH:{
- newHead=newCoordinate(head.x,head.y-1);
- break;
- }
- caseSOUTH:{
- newHead=newCoordinate(head.x,head.y+1);
- break;
- }
- }
- //Collisiondetection
- //Fornowwehavea1-squarewallaroundtheentirearena
- if((newHead.x<1)||(newHead.y<1)||(newHead.x>mXTileCount-2)
- ||(newHead.y>mYTileCount-2)){
- setMode(LOSE);
- return;
- }
- //Lookforcollisionswithitself
- intsnakelength=mSnakeTrail.size();
- for(intsnakeindex=0;snakeindex<snakelength;snakeindex++){
- Coordinatec=mSnakeTrail.get(snakeindex);
- if(c.equals(newHead)){
- setMode(LOSE);
- return;
- }
- }
- //Lookforapples
- //查找苹果设置苹果新的位置的信息
- intapplecount=mAppleList.size();
- for(intappleindex=0;appleindex<applecount;appleindex++){
- Coordinatec=mAppleList.get(appleindex);
- if(c.equals(newHead)){
- mAppleList.remove(c);
- addRandomApple();
- mScore++;
- //设置的移动的速度
- mMoveDelay*=0.9;
- growSnake=true;
- }
- }
- //将蛇头的位置信息放在第一个的对象中方取值
- //pushanewheadontotheArrayListandpulloffthetail
- mSnakeTrail.add(0,newHead);
- //exceptifwewantthesnaketogrow
- if(!growSnake){
- mSnakeTrail.remove(mSnakeTrail.size()-1);
- }
- intindex=0;
- for(Coordinatec:mSnakeTrail){
- if(index==0){
- setTile(YELLOW_STAR,c.x,c.y);
- }else{
- setTile(RED_STAR,c.x,c.y);
- }
- index++;
- }
- }
- /**
- *用于存储每一个位点的x,y坐标信息
- *Simpleclasscontainingtwointegervaluesandacomparisonfunction.
- *There'sprobablysomethingIshoulduseinstead,butthiswasquickand
- *easytobuild.
- *
- */
- privateclassCoordinate{
- publicintx;
- publicinty;
- publicCoordinate(intnewX,intnewY){
- x=newX;
- y=newY;
- }
- publicbooleanequals(Coordinateother){
- if(x==other.x&&y==other.y){
- returntrue;
- }
- returnfalse;
- }
- @Override
- publicStringtoString(){
- return"Coordinate:["+x+","+y+"]";
- }
- }
- }
更多相关文章
- Android中设置分割线
- Android(安卓)欢迎界面设置
- AndroidManifest.xml - activity 详细说明
- android根据字体大小设置控件高度
- Android(安卓)系统功能设置菜单 LinearLayout与relativeLayout的
- Android-Google自己的下拉刷新组件SwipeRefreshLayout
- 安卓开发09:常用控件-TextView文本展示
- Android(安卓)属性系统: Android(安卓)Property System
- Android(安卓)处理屏幕解锁和设置锁屏密码