一直想本身動手作一個手機遊戲,安裝在本身的手機上,儘管應用或許會看起來很簡單效果也不是很拉風,但是本身作的,那心情那感受終究是不同。今天,讓咱們一塊兒探祕貪吃蛇遊戲,用本身的雙手玩轉java代碼打造屬於本身的遊戲。java
貪吃蛇是一款足夠經典的遊戲。它的經典,在於用戶操做的簡單,在於技術實現的簡介,在於他的經久不衰,在於它的獨領風騷。android
這裏的貪吃蛇的android實現,是SDK Samples中的開源例程。可能各位都有看過-界面以下圖啦。。。canvas
做爲一個剛入門或者還沒入門的新手,着實花了我一些力氣來理解這段代碼。數組
對於各類不懂的地方,慢慢查詢資料,對於新的方法,經過修改代碼嘗試效果。到如今終於能算個只知其一;不知其二。安全
在代碼中,對於本身有所收穫的地方,我都作了相應的註釋。數據結構
回過頭來,以爲從這段代碼中,能學到很多東西~~架構
包括android應用的基本架構,他的面向對象的思想,以及代碼的簡潔明瞭。app
因而,我想到,何不將這些東西分享出來,若是碰巧對感興趣的朋友們有搜幫助,那就更好了~dom
好了,閒話不說~代碼和註釋以下(處於對源碼的敬意,本來的英文註釋部分都沒有刪去~你們能夠配合理解):異步
************************************************************************************************************************************
Snake工程中,總共有三個文件: *TileView是基於Android的View類實現的方塊圖類,用來支撐上層類的調用,繪製方塊圖的顯 示界面。經過這些代碼,能打之瞭解如何 擴展View,實現特點的界面效果。 *SnakeView調用了TileView,實現了遊戲邏輯 和 具體的顯示。 *Snake爲主Activity類。
建議你們按照上面的順序看三個文件,可能邏輯上更舒服一點~~
下面貼上代碼和註釋。
PS: 調試版本爲android2.2。 其餘版本應該也沒問題,不過得用虛擬機。
TileView.java
- 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;
-
-
-
-
-
-
-
-
- public class TileView extends View {
-
-
-
-
-
-
-
- protected static int mTileSize;
-
- protected static int mXTileCount;
- protected static int mYTileCount;
-
- private static int mXOffset;
- private static int mYOffset;
-
-
-
-
-
-
-
-
- private Bitmap[] mTileArray;
-
-
-
-
-
-
-
-
-
- private int[][] mTileGrid;
-
-
- private final Paint mPaint = new Paint();
-
-
- public TileView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- 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();
- }
-
-
-
-
-
-
-
-
-
-
- public void resetTiles(int tilecount) {
- mTileArray = new Bitmap[tilecount];
- }
-
-
-
-
-
-
- @Override
- protected 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();
- }
-
-
-
-
-
-
-
-
-
-
- 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;
- }
-
-
-
-
-
-
-
-
-
-
-
- public void setTile(int tileindex, int x, int y) {
- mTileGrid[x][y] = tileindex;
- }
-
-
-
-
-
-
-
- public void clearTiles() {
- for (int x = 0; x < mXTileCount; x++) {
- for (int y = 0; y < mYTileCount; y++) {
- setTile(0, x, y);
- }
- }
- }
-
-
-
-
-
- @Override
- public 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);
- }
- }
- }
- }
-
- }
SnakeView.java
- 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.TextView;
-
-
-
-
- public class SnakeView extends TileView {
-
- private static final String TAG = "SnakeView";
-
-
-
-
-
-
-
- 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;
-
-
-
-
-
- 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;
-
-
-
-
-
- private static final int RED_STAR = 1;
- private static final int YELLOW_STAR = 2;
- private static final int GREEN_STAR = 3;
-
-
-
-
-
-
- private long mScore = 0;
- private long mMoveDelay = 600;
-
-
-
-
-
-
-
-
- private long mLastMove;
-
-
-
-
-
-
- private TextView mStatusText;
-
-
-
-
-
-
-
- private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();
- private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>();
-
-
-
-
-
- private static final Random RNG = new Random();
-
-
-
-
-
-
-
-
-
- private RefreshHandler mRedrawHandler = new RefreshHandler();
-
- class RefreshHandler extends Handler {
-
-
- @Override
- public void handleMessage(Message msg) {
- SnakeView.this.update();
- SnakeView.this.invalidate();
- }
-
-
- public void sleep(long delayMillis) {
- this.removeMessages(0);
- sendMessageDelayed(obtainMessage(0), delayMillis);
- }
- };
-
-
-
- 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();
- 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();
-
-
-
-
-
- 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;
-
-
- addRandomApple();
- addRandomApple();
-
- mMoveDelay = 600;
- mScore = 0;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- private int[] coordArrayListToArray(ArrayList<Coordinate> 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;
- }
-
-
-
-
-
-
-
-
- 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;
- }
-
-
-
-
-
-
-
-
- private ArrayList<Coordinate> coordArrayToArrayList(int[] rawArray) {
- ArrayList<Coordinate> coordArrayList = new ArrayList<Coordinate>();
-
- 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;
- }
-
-
-
-
-
-
- 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"));
- }
-
-
-
-
-
-
-
-
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent msg) {
-
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- if (mMode == READY | mMode == LOSE) {
-
-
-
-
- initNewGame();
- setMode(RUNNING);
- update();
- return (true);
- }
-
- if (mMode == PAUSE) {
-
-
-
-
- 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);
- }
-
-
-
-
-
-
- public void setTextView(TextView newView) {
- mStatusText = newView;
- }
-
-
-
-
-
-
-
- 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);
- }
-
-
-
-
-
-
-
-
-
-
- private void addRandomApple() {
- Coordinate newCoord = null;
- boolean found = false;
- while (!found) {
-
-
- int newX = 1 + RNG.nextInt(mXTileCount - 2);
- int newY = 1 + RNG.nextInt(mYTileCount - 2);
- newCoord = new Coordinate(newX, newY);
-
-
- boolean collision = false;
- int snakelength = mSnakeTrail.size();
- for (int index = 0; index < snakelength; index++) {
- if (mSnakeTrail.get(index).equals(newCoord)) {
- collision = true;
- }
- }
-
-
-
- found = !collision;
- }
- if (newCoord == null) {
- Log.e(TAG, "Somehow ended up with a null newCoord!");
- }
- mAppleList.add(newCoord);
- }
-
-
-
-
-
-
-
- public void update() {
- if (mMode == RUNNING) {
- long now = System.currentTimeMillis();
-
- if (now - mLastMove > mMoveDelay) {
-
- clearTiles();
- updateWalls();
- updateSnake();
- updateApples();
- mLastMove = now;
- }
- mRedrawHandler.sleep(mMoveDelay);
- }
-
- }
-
-
-
-
-
- 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);
- }
- }
-
-
-
-
-
- private void updateApples() {
- for (Coordinate c : mAppleList) {
- setTile(YELLOW_STAR, c.x, c.y);
- }
- }
-
-
-
-
-
-
-
-
- private void updateSnake() {
- boolean growSnake = false;
-
-
- Coordinate 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;
- }
- }
-
-
-
-
- if ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2)
- || (newHead.y > mYTileCount - 2)) {
- setMode(LOSE);
- return;
-
- }
-
-
-
- int snakelength = mSnakeTrail.size();
- for (int snakeindex = 0; snakeindex < snakelength; snakeindex++) {
- Coordinate c = mSnakeTrail.get(snakeindex);
- if (c.equals(newHead)) {
- setMode(LOSE);
- return;
- }
- }
-
-
-
- int 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;
- }
- }
-
-
-
- mSnakeTrail.add(0, newHead);
-
- if (!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++;
- }
-
- }
-
-
-
-
-
-
-
- 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;
- }
-
- @Override
- public String toString() {
- return "Coordinate: [" + x + "," + y + "]";
- }
- }
-
- }
Snake.java
- package com.example.android.snake;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.Window;
- import android.widget.TextView;
-
-
-
-
-
-
-
-
-
- public class Snake extends Activity {
-
-
- private SnakeView mSnakeView;
-
- private static String ICICLE_KEY = "snake-view";
-
-
-
-
-
-
- @Override
- public 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));
-
- if (savedInstanceState == null) {
-
- mSnakeView.setMode(SnakeView.READY);
- } else {
-
- Bundle map = savedInstanceState.getBundle(ICICLE_KEY);
- if (map != null) {
- mSnakeView.restoreState(map);
- } else {
- mSnakeView.setMode(SnakeView.PAUSE);
- }
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- mSnakeView.setMode(SnakeView.PAUSE);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
-
- outState.putBundle(ICICLE_KEY, mSnakeView.saveState());
- }
-
- }