最近项目特别紧。不过自己似乎很乐意每天加班。加班回家继续coding

一种是工作。一种是生活

------------------------------------------------------我是分割线-------------------------------------------------

起因:之前很久就看到贪吃蛇这个游戏。但是google给的例子还是2.2时候的例子。并且还用着模拟器上的方向键来控制。

还是应验了那句话。自己动手。乐趣无穷。

所以:今天就来好好说说这个小游戏。并且加以改进下。

------------------------------------------------------我是分割线-------------------------------------------------

首先如果让你自己做这个游戏。你会怎么做呢。其实你会怎么做我是不知道。

不过从面向对象的角度出发的话。那么三个东西是不可少的。

蛇。苹果。墙(地图)。操作者。

google的开发者也是这么想。

那么就先看那些大湿是怎么来考虑这个问题的。(为了缩减篇幅,我就删了一些声明的语句)

/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.android.snake;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;/** * TileView: a View-variant designed for handling arrays of "icons" or other * drawables. 首先tile是有瓦的意思。用一个个tile拼接起来的就是地图。tileview就是用来呈现地图的类 */public class TileView extends View {/** * Parameters controlling the size of the tiles and their range within view. * Width/Height are in pixels, and Drawables will be scaled to fit to these * dimensions. X/Y Tile Counts are the number of tiles that will be drawn. */protected static int mTileSize; // 地图tile的大小。其实就是点的宽和高(是一样的值)protected static int mXTileCount;// 地图上x轴能够容纳的tile的数量。下面类似protected static int mYTileCount;private static int mXOffset;// 地图的起始坐标private static int mYOffset;/** * A hash that maps integer handles specified by the subclasser to the * drawable that will be used for that reference */private Bitmap[] mTileArray;// 地图上tile对应的图片数组。每一种tile都对应一个bitmap。比如mTileArray[1]就是草地的bitmap。可以类推。/** * A two-dimensional array of integers in which the number represents the * index of the tile that should be drawn at that locations */private int[][] mTileGrid;// 地图上的tile的数组。比如int[1][1]=0说明这个点是草地。int[1][2]=1说明这个点是苹果// 其实思想就是这么简单。方式可以有各种各样private final Paint mPaint = new Paint();// 画笔。画图需要笔来画。应该很容易理解。各种笔。黑色。红色。public TileView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// 这里用到的TypeArray。不懂的童鞋要去google下。是google弄出来的一种样式数组,其实就像定义一个控件的属性的集合。TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);a.recycle();}public TileView(Context context, AttributeSet attrs) {super(context, attrs);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);a.recycle();}/** * Rests the internal array of Bitmaps used for drawing tiles, and sets the * maximum index of tiles to be inserted *  * @param tilecount */public void resetTiles(int tilecount) {mTileArray = new Bitmap[tilecount];}// 个人认为。这个函数是比较有意思的。这个是view的一个回调函数。最开始初始话的时候view的大小都是0。当进行layout之后。每个view都确定了大小。这样就开始回调这个函数。@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {mXTileCount = (int) Math.floor(w / mTileSize);mYTileCount = (int) Math.floor(h / mTileSize);mXOffset = ((w - (mTileSize * mXTileCount)) / 2);mYOffset = ((h - (mTileSize * mYTileCount)) / 2);mTileGrid = new int[mXTileCount][mYTileCount];clearTiles();}/** * Function to set the specified Drawable as the tile for a particular * integer key. *  * @param key * @param tile *            这函数就是根据Key代表tile种类。来加载地图tile的图片(这里是一个drawable。要变成bitmap) */public void loadTile(int key, Drawable tile) {Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);tile.setBounds(0, 0, mTileSize, mTileSize);tile.draw(canvas);mTileArray[key] = bitmap;}/** * Resets all tiles to 0 (empty) *  */public void clearTiles() {for (int x = 0; x < mXTileCount; x++) {for (int y = 0; y < mYTileCount; y++) {setTile(0, x, y);}}}/** * Used to indicate that a particular tile (set with loadTile and referenced * by an integer) should be drawn at the given x/y coordinates during the * next invalidate/draw cycle. *  * @param tileindex * @param x * @param y *  这边就是设置每一个tile(地图上的点)对应的是哪一种图片。这里的tileindex就是代表了mTileArray[]中的index */public void setTile(int tileindex, int x, int y) {mTileGrid[x][y] = tileindex;}// 这个函数就是画出地图了。遍历地图的点,然后把每个tile的坐标都计算出来,然后一个个的tile都draw到canvas上哈@Overridepublic void onDraw(Canvas canvas) {super.onDraw(canvas);for (int x = 0; x < mXTileCount; x += 1) {for (int y = 0; y < mYTileCount; y += 1) {if (mTileGrid[x][y] > 0) {canvas.drawBitmap(mTileArray[mTileGrid[x][y]], mXOffset + x * mTileSize, mYOffset + y * mTileSize, mPaint);}}}}}


 这里要补充的就是。其实贪吃蛇和苹果也可以作为地图上的一部分。   

但是它们是特殊的。实际上只是表示的点的图片不一样。

------------------------------------------------------我是分割线-------------------------------------------------

估计google的开发者写完了这个之后就想了。那要想想蛇和苹果了。

哈哈。感觉有点胡乱猜测之意了。

不过呢。一开始对这个游戏全局考虑的时候。

会发现。其实苹果和蛇抽象出来。其实就是分别是一个数组。

比如AppleList[]和SnakeList[]。前者存放每一个苹果的坐标。

比如AppleList[0]={x1 y1}。说明x1 y1这个点是苹果。

理解了思想就简单了。

下面看SnakeView.java

/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.android.snake;import java.util.ArrayList;import java.util.Random;import android.content.Context;import android.content.res.Resources;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.os.Bundle;import android.util.Log;import android.view.KeyEvent;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.view.View.OnClickListener;/** * SnakeView: implementation of a simple game of Snake * 首先。这个类继承的是TileView。说明整个游戏的画面最后都能通过tile这个元素来表达。 * 也就是所有的东西都可以通过tile来提现。这个就是整个工程的核心思想。 */public class SnakeView extends TileView implements OnClickListener {private static final String TAG = "SnakeView";/** * Current mode of application: READY to run, RUNNING, or you have already * lost. static final ints are used instead of an enum for performance * reasons. */private int mMode = READY;// 这个是游戏的5中状态。public static final int PAUSE = 0;public static final int READY = 1;public static final int RUNNING = 2;public static final int LOSE = 3;/** * Current direction the snake is headed. */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;/** * Labels for the drawables that will be loaded into the TileView class */private static final int RED_STAR = 1;// 这三个标签分别来表示不同的tile的drawable。比如RED_STAR代表的是蛇的身子的点(tile)private static final int YELLOW_STAR = 2;private static final int GREEN_STAR = 3;/** * mScore: used to track the number of apples captured mMoveDelay: number of * milliseconds between snake movements. This will decrease as apples are * captured. */private long mScore = 0; // 成绩,吃了多少的苹果private long mMoveDelay = 600;// 间隔多少毫秒进行移动一次/** * mLastMove: tracks the absolute time when the snake last moved, and is * used to determine if a move should be made based on mMoveDelay. */private long mLastMove; // 上一次移动的时刻/** * mStatusText: text shows to the user in some run states */private TextView mStatusText;// 这个是开始的时候的提示语/** * mSnakeTrail: a list of Coordinates that make up the snake's body * mAppleList: the secret location of the juicy apples the snake craves. */private ArrayList mSnakeTrail = new ArrayList();// 蛇的所有(点)tile的坐标数组private ArrayList mAppleList = new ArrayList();// 苹果的所有(点)tile的坐标数组/** * Everyone needs a little randomness in their life */private static final Random RNG = new Random();// 随机数/** * Create a simple handler that we can use to cause animation to happen. We * set ourselves as a target and we can use the sleep() function to cause an * update/invalidate to occur at a later date. */private RefreshHandler mRedrawHandler = new RefreshHandler();// 重点说下这边吧。其实整个工程最精华的地方。除了上面说的。就是这里了。这个刷新的handler。(如果不明白Handler的童鞋。强烈建议读源码。)// 通过这个Handler给自己发送消息。比如延迟30秒给自己发一个消息。这样就实现了一个循环。很聪明的想法。private Button mStart; // 下面的五个按钮分别是我加的。因为原来的只能响应上下左右键的操作。这边是满足触屏的操作效果。可以在布局文件中看相关的布局。private Button mLeft;private Button mRight;private Button mTop;private Button mBottom;// 下面整个工程巧妙的地方了。调用了sleep。然后延迟delayMillis秒之后,发送自己一个消息。然后这个消息在handleMessage中被处理了。// 处理的过程,调用了update函数,update函数又调用了sleep函数。这样一个完美的循环就开始了。class RefreshHandler extends Handler {@Overridepublic void handleMessage(Message msg) {SnakeView.this.update();SnakeView.this.invalidate();}public void sleep(long delayMillis) {this.removeMessages(0);sendMessageDelayed(obtainMessage(0), delayMillis);}};/** * Constructs a SnakeView based on inflation from XML *  * @param context * @param attrs */public SnakeView(Context context, AttributeSet attrs) {super(context, attrs);initSnakeView();}public SnakeView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initSnakeView();}private void initSnakeView() {setFocusable(true);Resources r = this.getContext().getResources();// 设置了tile的类型有四种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();// For now we're just going to load up a short default eastbound snake// that's just turned north// 初始化蛇的坐标mSnakeTrail.add(new Coordinate(7, 30));mSnakeTrail.add(new Coordinate(6, 30));mSnakeTrail.add(new Coordinate(5, 30));mSnakeTrail.add(new Coordinate(4, 30));mSnakeTrail.add(new Coordinate(3, 30));mSnakeTrail.add(new Coordinate(2, 30));// 蛇移动的方向mNextDirection = NORTH;// Two apples to start with// 增加两个随机的苹果addRandomApple();addRandomApple();mMoveDelay = 100;mScore = 0;}/** * Given a ArrayList of coordinates, we need to flatten them into an array * of ints before we can stuff them into a map for flattening and storage. *  * @param cvec *            : a ArrayList of Coordinate objects * @return : a simple array containing the x/y values of the coordinates as *         [x1,y1,x2,y2,x3,y3...] 这是一个坐标的数组转化成一维数组的函数。还有一个函数是相反的。 */private int[] coordArrayListToArray(ArrayList cvec) {int count = cvec.size();int[] rawArray = new int[count * 2];for (int index = 0; index < count; index++) {Coordinate c = cvec.get(index);rawArray[2 * index] = c.x;rawArray[2 * index + 1] = c.y;}return rawArray;}/** * Save game state so that the user does not lose anything if the game * process is killed while we are in the background. *  * @return a Bundle with this view's state */public Bundle saveState() {Bundle map = 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;}/** * Given a flattened array of ordinate pairs, we reconstitute them into a * ArrayList of Coordinate objects *  * @param rawArray *            : [x1,y1,x2,y2,...] * @return a ArrayList of Coordinates */private ArrayList coordArrayToArrayList(int[] rawArray) {ArrayList coordArrayList = new ArrayList();int coordCount = rawArray.length;for (int index = 0; index < coordCount; index += 2) {Coordinate c = new Coordinate(rawArray[index], rawArray[index + 1]);coordArrayList.add(c);}return coordArrayList;}/** * Restore game state if our process is being relaunched *  * @param icicle *            a Bundle containing the game state *            储存游戏的数据。比如游戏中。按了home切出去了。这样就可以保存游戏的数据。切回来时就能继续。 */public void restoreState(Bundle icicle) {setMode(PAUSE);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"));}/* * handles key events in the game. Update the direction our snake is * traveling based on the DPAD. Ignore events that would cause the snake to * immediately turn back on itself. *  * (non-Javadoc) *  * @see android.view.View#onKeyDown(int, android.os.KeyEvent) */@Overridepublic boolean onKeyDown(int keyCode, KeyEvent msg) {if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {if (mMode == READY | mMode == LOSE) {/* * At the beginning of the game, or the end of a previous one, * we should start a new game. */initNewGame();setMode(RUNNING);update();return (true);}if (mMode == PAUSE) {/* * If the game is merely paused, we should just continue where * we left off. */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);}/** * Sets the TextView that will be used to give information (such as "Game * Over" to the user. *  * @param newView */public void setTextView(TextView newView) {mStatusText = newView;}public void setStartButton(Button button) {mStart = button;mStart.setOnClickListener(this);}/** * Updates the current mode of the application (RUNNING or PAUSED or the * like) as well as sets the visibility of textview for notification *  * @param newMode *            设置向前的游戏状态 */public void setMode(int newMode) {int oldMode = mMode;mMode = newMode;if (newMode == RUNNING & oldMode != RUNNING) {mStatusText.setVisibility(View.INVISIBLE);update();return;}Resources res = getContext().getResources();CharSequence str = "";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);mStart.setVisibility(View.VISIBLE);mLeft.setVisibility(View.INVISIBLE);mRight.setVisibility(View.INVISIBLE);mTop.setVisibility(View.INVISIBLE);mBottom.setVisibility(View.INVISIBLE);}/** * Selects a random location within the garden that is not currently covered * by the snake. Currently _could_ go into an infinite loop if the snake * currently fills the garden, but we'll leave discovery of this prize to a * truly excellent snake-player. *  */private void addRandomApple() {Coordinate newCoord = null;boolean found = false;while (!found) {// Choose a new location for our appleint newX = 1 + RNG.nextInt(mXTileCount - 2);int newY = 1 + RNG.nextInt(mYTileCount - 2);newCoord = new Coordinate(newX, newY);// Make sure it's not already under the snakeboolean collision = false;int snakelength = mSnakeTrail.size();for (int index = 0; index < snakelength; index++) {if (mSnakeTrail.get(index).equals(newCoord)) {collision = true;}}// if we're here and there's been no collision, then we have// a good location for an apple. Otherwise, we'll circle back// and try againfound = !collision;}if (newCoord == null) {Log.e(TAG, "Somehow ended up with a null newCoord!");}mAppleList.add(newCoord);}/** * Handles the basic update loop, checking to see if we are in the running * state, determining if a move should be made, updating the snake's * location. */public void update() {if (mMode == RUNNING) {long now = System.currentTimeMillis();if (now - mLastMove > mMoveDelay) {clearTiles();updateWalls();updateSnake();updateApples();mLastMove = now;}mRedrawHandler.sleep(mMoveDelay);}}/** * Draws some walls. 画出四周的墙 */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);}}/** * Draws some apples. 画出苹果 */private void updateApples() {for (Coordinate c : mAppleList) {setTile(YELLOW_STAR, c.x, c.y);}}/** * Figure out which way the snake is going, see if he's run into anything * (the walls, himself, or an apple). If he's not going to die, we then add * to the front and subtract from the rear in order to simulate motion. If * we want to grow him, we don't subtract from the rear. 更新蛇。其实就是产生蛇移动的效果。 */private void updateSnake() {boolean growSnake = false;// grab the snake by the headCoordinate head = mSnakeTrail.get(0);Coordinate newHead = 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;}}// Collision detection// For now we have a 1-square wall around the entire arenaif ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2) || (newHead.y > mYTileCount - 2)) {setMode(LOSE);return;}// Look for collisions with itselfint snakelength = mSnakeTrail.size();for (int snakeindex = 0; snakeindex < snakelength; snakeindex++) {Coordinate c = mSnakeTrail.get(snakeindex);if (c.equals(newHead)) {setMode(LOSE);return;}}// Look for applesint applecount = mAppleList.size();for (int appleindex = 0; appleindex < applecount; appleindex++) {Coordinate c = mAppleList.get(appleindex);if (c.equals(newHead)) {mAppleList.remove(c);addRandomApple();mScore++;mMoveDelay *= 0.9;growSnake = true;}}// push a new head onto the ArrayList and pull off the tailmSnakeTrail.add(0, newHead);// except if we want the snake to growif (!growSnake) {mSnakeTrail.remove(mSnakeTrail.size() - 1);}int index = 0;for (Coordinate c : mSnakeTrail) {if (index == 0) {setTile(YELLOW_STAR, c.x, c.y);} else {setTile(RED_STAR, c.x, c.y);}index++;}}/** * Simple class containing two integer values and a comparison function. * There's probably something I should use instead, but this was quick and * easy to build. 坐标的类 */private class Coordinate {public int x;public int y;public Coordinate(int newX, int newY) {x = newX;y = newY;}public boolean equals(Coordinate other) {if (x == other.x && y == other.y) {return true;}return false;}@Overridepublic String toString() {return "Coordinate: [" + x + "," + y + "]";}}// 这是我加的。是一个简单的响应上下左右的点击。可以触屏玩游戏。public void onClick(View v) {switch (v.getId()) {case R.id.start:if (mMode == READY | mMode == LOSE) {initNewGame();setMode(RUNNING);update();mStart.setVisibility(View.GONE);mLeft.setVisibility(View.VISIBLE);mRight.setVisibility(View.VISIBLE);mTop.setVisibility(View.VISIBLE);mBottom.setVisibility(View.VISIBLE);}if (mMode == PAUSE) {setMode(RUNNING);update();mStart.setVisibility(View.GONE);mLeft.setVisibility(View.VISIBLE);mRight.setVisibility(View.VISIBLE);mTop.setVisibility(View.VISIBLE);mBottom.setVisibility(View.VISIBLE);}break;case R.id.left:if (mDirection != EAST) {mNextDirection = WEST;}break;case R.id.right:if (mDirection != WEST) {mNextDirection = EAST;}break;case R.id.top:if (mDirection != SOUTH) {mNextDirection = NORTH;}break;case R.id.bottom:if (mDirection != NORTH) {mNextDirection = SOUTH;}break;default:break;}}// 设置方向键public void setControlButton(Button left, Button right, Button top, Button bottom) {mLeft = left;mRight = right;mTop = top;mBottom = bottom;mLeft.setOnClickListener(this);mRight.setOnClickListener(this);mTop.setOnClickListener(this);mBottom.setOnClickListener(this);}}

最重要的东西就是上面这个类了。看代码始终是比较爽的。

------------------------------------------------------我是分割线-------------------------------------------------

剩下就是启动的Activity了。简单的分析下吧。

/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.android.snake;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.Window;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;/** * Snake: a simple game that everyone can enjoy. *  * This is an implementation of the classic Game "Snake", in which you control a * serpent roaming around the garden looking for apples. Be careful, though, * because when you catch one, not only will you become longer, but you'll move * faster. Running into yourself or the walls will end the game. *  */public class Snake extends Activity {private SnakeView mSnakeView;private Button mStart;private static String ICICLE_KEY = "snake-view";/** * Called when Activity is first created. Turns off the title bar, sets up * the content views, and fires up the SnakeView. *  */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.snake_layout);mSnakeView = (SnakeView) findViewById(R.id.snake);mSnakeView.setTextView((TextView) findViewById(R.id.text));mSnakeView.setStartButton((Button) findViewById(R.id.start));mSnakeView.setControlButton((Button) findViewById(R.id.left), (Button) findViewById(R.id.right),(Button) findViewById(R.id.top), (Button) findViewById(R.id.bottom));// 判断下数据是否有保存,没有的话,就重新开始游戏if (savedInstanceState == null) {// We were just launched -- set up a new gamemSnakeView.setMode(SnakeView.READY);} else {// We are being restoredBundle map = savedInstanceState.getBundle(ICICLE_KEY);if (map != null) {mSnakeView.restoreState(map);} else {mSnakeView.setMode(SnakeView.PAUSE);}}}@Overrideprotected void onPause() {super.onPause();// Pause the game along with the activitymSnakeView.setMode(SnakeView.PAUSE);}@Overridepublic void onSaveInstanceState(Bundle outState) {// Store the game stateoutState.putBundle(ICICLE_KEY, mSnakeView.saveState());}}

上面的代码唯一需要说明的就是。游戏的过程中有可能按了Home键切出去了。

但是为了保证游戏的连续性。所以要在启动的时候做一下判断。

是否之前有保存的数据。如果是通过(比如长按Home键切回来)。

那么这时候就恢复数据。呈现出暂定的状态。

这也是这个游戏值得学习的地方。

------------------------------------------------------我是分割线-------------------------------------------------

其实说了这么多。一直没说过改进。

我所做的不多。就是多了一个开始的按钮和四个方向键。

然后触屏也能够体验下这款游戏。

对了。我的工程有一个不足的地方就是。

方向键不是透明的效果。这样如果苹果是在方向键的下面。

就会吃不到苹果。换一个透明度为20的就行了。

后面会改进的。

------------------------------------------------------我是分割线-------------------------------------------------

很久没有写这种技术博客了。并且我写的很多东西。

大概网上很多人也都说过。也懂得。

只是觉得一直以来自己从别人那里得到了很多。

或者自己也应该去帮助下那些可能需要帮助的人。

任何小事都贵在坚持。

这仅仅是一个开始。

后面的是附图:


完整工程下载地址:http://download.csdn.net/detail/ruan_xiao/4519287

更多相关文章

  1. 【开源项目12】Retrofit – Java(Android) 的REST 接口封装类库
  2. [转载] android中的surface
  3. 快速实现android手机端多人视频会议直播(免费)
  4. Android应用开发基础篇(1)-----Button
  5. Android创建服务之started service
  6. Android(安卓)Binder机制(2) ContextManager注册过程分析
  7. Android(安卓)-- 小功能 如何处理未捕获异常
  8. Android:保存图片到Sqlite数据库
  9. 自定义View之onMeasure()

随机推荐

  1. 2020-12-24
  2. 自定义Android注解Part1:注解变量
  3. 三星败诉,Android必将迎来新一轮洗牌
  4. Emulator: PANIC: Cannot find AVD syste
  5. OpenGL ES for Android 播放视频
  6. Gradle(一)基本概念
  7. Android 手机屏幕那些事儿
  8. Android跟蓝牙耳机建立连接有两种方式
  9. Android:媒体播放器
  10. 你不应该错过的 Android(安卓)全方位面试