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元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
