Android中貪吃蛇游戲的學習(三)
文章分類: 移動開發
視圖VIew的類的Snake的,主要關注的學習的類。
- package com.easyway.dev.android.snake;
 - import java.util.ArrayList;
 - import java.util.Random;
 - import android.content.Context;
 - import android.content.res.Resources;
 - import android.os.Bundle;
 - import android.os.Handler;
 - import android.os.Message;
 - import android.util.AttributeSet;
 - import android.util.Log;
 - import android.view.KeyEvent;
 - import android.view.View;
 - import android.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可以被重載或被按著我們的習慣定制。
 - *
 - */
 - public class SnakeView extends TileView{
 - private static final StringTAG= "SnakeView" ;
 - /**
 - *Currentmodeofapplication:READYtorun,RUNNING,oryouhavealready
 - *lost.staticfinalintsareusedinsteadofanenumforperformance
 - *reasons.
 - */
 - private int mMode=READY;
 - public static final int PAUSE= 0 ;
 - public static final int READY= 1 ;
 - public static final int RUNNING= 2 ;
 - public static final int LOSE= 3 ;
 - /**
 - *設置方向
 - *Currentdirectionthesnakeisheaded.
 - */
 - private int mDirection=NORTH;
 - private int mNextDirection=NORTH;
 - private static final int NORTH= 1 ;
 - private static final int SOUTH= 2 ;
 - private static final int EAST= 3 ;
 - private static final int WEST= 4 ;
 - /**
 - *LabelsforthedrawablesthatwillbeloadedintotheTileViewclass
 - */
 - private static final int RED_STAR= 1 ;
 - private static final int YELLOW_STAR= 2 ;
 - private static final int GREEN_STAR= 3 ;
 - /**
 - *mScore:usedtotrackthenumberofapplescapturedmMoveDelay:numberof
 - *millisecondsbetweensnakemovements.Thiswilldecreaseasapplesare
 - *captured.
 - */
 - private long mScore= 0 ;
 - private long mMoveDelay= 600 ;
 - /**
 - *mLastMove:trackstheabsolutetimewhenthesnakelastmoved,andisused
 - *todetermineifamoveshouldbemadebasedonmMoveDelay.
 - */
 - private long mLastMove;
 - /**
 - *mStatusText:textshowstotheuserinsomerunstates
 - */
 - private TextViewmStatusText;
 - /**
 - *用于存儲貪吃蛇中,蘋果和蛇的點陣的坐標的信息的集合
 - *mSnakeTrail:alistofCoordinatesthatmakeupthesnake'sbody
 - *mAppleList:thesecretlocationofthejuicyapplesthesnakecraves.
 - */
 - private ArrayList<Coordinate>mSnakeTrail= new ArrayList<Coordinate>();
 - private ArrayList<Coordinate>mAppleList= new ArrayList<Coordinate>();
 - /**
 - *為創建蘋果坐標使用隨機對象
 - *Everyoneneedsalittlerandomnessintheirlife
 - */
 - private static final RandomRNG= new Random();
 - /**
 - *刷新界面處理器
 - *Createasimplehandlerthatwecanusetocauseanimationtohappen.We
 - *setourselvesasatargetandwecanusethesleep()
 - *functiontocauseanupdate/invalidatetooccuratalaterdate.
 - */
 - private RefreshHandlermRedrawHandler= new RefreshHandler();
 - /**
 - *實現刷新的功能:
 - *在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
 - */
 - class RefreshHandler extends Handler{
 - /**
 - *響應消息
 - */
 - @Override
 - public void handleMessage(Messagemsg){
 - SnakeView. this .update();
 - SnakeView. this .invalidate();
 - }
 - /**
 - *向外提供人工的調用消息的接口
 - *@paramdelayMillis
 - */
 - public void sleep( long delayMillis){
 - //注銷消息
 - this .removeMessages( 0 );
 - //添加消息
 - sendMessageDelayed(obtainMessage( 0 ),delayMillis);
 - }
 - };
 - /**
 - *ConstructsaSnakeViewbasedoninflationfromXML
 - *
 - *@paramcontext
 - *@paramattrs
 - */
 - public SnakeView(Contextcontext,AttributeSetattrs){
 - super (context,attrs);
 - initSnakeView();
 - }
 - public SnakeView(Contextcontext,AttributeSetattrs, int defStyle){
 - super (context,attrs,defStyle);
 - initSnakeView();
 - }
 - /**
 - *初始化界面的
 - */
 - private void initSnakeView(){
 - 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));
 - }
 - /**
 - *初始化新的游戲
 - */
 - private void initNewGame(){
 - mSnakeTrail.clear();
 - mAppleList.clear();
 - //Fornowwe'rejustgoingtoloadupashortdefaulteastboundsnake
 - //that'sjustturnednorth
 - //設置初始化蛇的位置
 - mSnakeTrail.add( new Coordinate( 7 , 7 ));
 - mSnakeTrail.add( new Coordinate( 6 , 7 ));
 - mSnakeTrail.add( new Coordinate( 5 , 7 ));
 - mSnakeTrail.add( new Coordinate( 4 , 7 ));
 - mSnakeTrail.add( new Coordinate( 3 , 7 ));
 - mSnakeTrail.add( new Coordinate( 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...]
 - */
 - private int []coordArrayListToArray(ArrayList<Coordinate>cvec){
 - int count=cvec.size();
 - int []rawArray= new int [count* 2 ];
 - for ( int index= 0 ;index<count;index++){
 - Coordinatec=cvec.get(index);
 - rawArray[ 2 *index]=c.x;
 - rawArray[ 2 *index+ 1 ]=c.y;
 - }
 - return rawArray;
 - }
 - /**
 - *Savegamestatesothattheuserdoesnotloseanything
 - *ifthegameprocessiskilledwhileweareinthe
 - *background.
 - *
 - *@returnaBundlewiththisview'sstate
 - */
 - public BundlesaveState(){
 - Bundlemap= new Bundle();
 - 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));
 - return map;
 - }
 - /**
 - *Givenaflattenedarrayofordinatepairs,wereconstitutethemintoa
 - *ArrayListofCoordinateobjects
 - *
 - *@paramrawArray:[x1,y1,x2,y2,...]
 - *@returnaArrayListofCoordinates
 - */
 - private ArrayList<Coordinate>coordArrayToArrayList( int []rawArray){
 - ArrayList<Coordinate>coordArrayList= new ArrayList<Coordinate>();
 - int coordCount=rawArray.length;
 - for ( int index= 0 ;index<coordCount;index+= 2 ){
 - Coordinatec= new Coordinate(rawArray[index],rawArray[index+ 1 ]);
 - coordArrayList.add(c);
 - }
 - return coordArrayList;
 - }
 - /**
 - *Restoregamestateifourprocessisbeingrelaunched
 - *
 - *@paramicicleaBundlecontainingthegamestate
 - */
 - public void restoreState(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
 - public boolean onKeyDown( int keyCode,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 );
 - }
 - return super .onKeyDown(keyCode,msg);
 - }
 - /**
 - *SetstheTextViewthatwillbeusedtogiveinformation(suchas"Game
 - *Over"totheuser.
 - *
 - *@paramnewView
 - */
 - public void setTextView(TextViewnewView){
 - mStatusText=newView;
 - }
 - /**
 - *Updatesthecurrentmodeoftheapplication(RUNNINGorPAUSEDorthelike)
 - *aswellassetsthevisibilityoftextviewfornotification
 - *
 - *@paramnewMode
 - */
 - public void setMode( int newMode){
 - int oldMode=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.
 - *
 - */
 - private void addRandomApple(){
 - CoordinatenewCoord= null ;
 - boolean found= false ;
 - while (!found){
 - //隨機生成新的X,Y位置
 - //Chooseanewlocationforourapple
 - int newX= 1 +RNG.nextInt(mXTileCount- 2 );
 - int newY= 1 +RNG.nextInt(mYTileCount- 2 );
 - newCoord= new Coordinate(newX,newY);
 - //Makesureit'snotalreadyunderthesnake
 - boolean collision= false ;
 - int snakelength=mSnakeTrail.size();
 - for ( int index= 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.
 - */
 - public void update(){
 - if (mMode==RUNNING){
 - long now=System.currentTimeMillis();
 - if (now-mLastMove>mMoveDelay){
 - clearTiles();
 - updateWalls();
 - updateSnake();
 - updateApples();
 - mLastMove=now;
 - }
 - mRedrawHandler.sleep(mMoveDelay);
 - }
 - }
 - /**
 - *調用以上的方法以循環的方式位置數組賦值以及圖片的索引。
 - *
 - *Drawssomewalls.
 - *
 - */
 - private void updateWalls(){
 - for ( int x= 0 ;x<mXTileCount;x++){
 - setTile(GREEN_STAR,x, 0 ); //設置頂部的界限的位置
 - setTile(GREEN_STAR,x,mYTileCount- 1 ); //設置底部界限的位置
 - }
 - for ( int y= 1 ;y<mYTileCount- 1 ;y++){
 - setTile(GREEN_STAR, 0 ,y); //設置頂部的界限的位置
 - setTile(GREEN_STAR,mXTileCount- 1 ,y); //設置底部界限的位置
 - }
 - }
 - /**
 - *Drawssomeapples.
 - *
 - */
 - private void updateApples(){
 - 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.
 - *
 - */
 - private void updateSnake(){
 - boolean growSnake= false ;
 - //grabthesnakebythehead
 - //獲取蛇的頭部
 - Coordinatehead=mSnakeTrail.get( 0 );
 - //創建一個新的蛇的頭部應該的位置
 - CoordinatenewHead= new Coordinate( 1 , 1 );
 - //根據當前的為方向設置坐標的信息
 - mDirection=mNextDirection;
 - switch (mDirection){
 - case EAST:{
 - newHead= new Coordinate(head.x+ 1 ,head.y);
 - break ;
 - }
 - case WEST:{
 - newHead= new Coordinate(head.x- 1 ,head.y);
 - break ;
 - }
 - case NORTH:{
 - newHead= new Coordinate(head.x,head.y- 1 );
 - break ;
 - }
 - case SOUTH:{
 - newHead= new Coordinate(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
 - int snakelength=mSnakeTrail.size();
 - for ( int snakeindex= 0 ;snakeindex<snakelength;snakeindex++){
 - Coordinatec=mSnakeTrail.get(snakeindex);
 - if (c.equals(newHead)){
 - setMode(LOSE);
 - return ;
 - }
 - }
 - //Lookforapples
 - //查找蘋果設置蘋果新的位置的信息
 - int applecount=mAppleList.size();
 - for ( int appleindex= 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 );
 - }
 - int index= 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.
 - *
 - */
 - private class Coordinate{
 - public int x;
 - public int y;
 - public Coordinate( int newX, int newY){
 - x=newX;
 - y=newY;
 - }
 - public boolean equals(Coordinateother){
 - if (x==other.x&&y==other.y){
 - return true ;
 - }
 - return false ;
 - }
 - @Override
 - public StringtoString(){
 - return "Coordinate:[" +x+ "," +y+ "]" ;
 - }
 - }
 - }
 
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
					微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
					
