Android App 源码分析(贪吃蛇游戏)

 

——/android-sdk-windows/samples/android-7/Snake


首届 Google 暑期大学生博客分享大赛——2010 Andriod 篇


Snake源码由三部分组成:Snake.java,SnakeView.java,TileView.java

1. Snake.java

Snake.java是整个整个贪吃蛇游戏的主框架;主要负责程序界面的初始化,游戏的初始化及负责游戏暂停或载入游戏的状态。

a.界面初始化

setContentView(R.layout.snake_layout);

mSnakeView = (SnakeView) findViewById(R.id.snake);

mSnakeView.setTextView((TextView) findViewById(R.id.text));

/** R.layout.snake_layout 指向的snake_layout.xml是游戏的UI设定,在FrameLayout中包含了两个元素:com.example.android.snake.SnakeView(这是个画布)TextView(用来显示文字)*/

b.游戏初始化及载入游戏状态

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); //暂停

             }

      }

}

2. TiltView.java

TiltView的基类是View,包含了贪吃蛇游戏画面的各个设定参数,主要负责绘制游戏画面。

    protected static int mTileSize;//方格的边长

    protected static int mXTileCount;//X轴上方格的个数

    protected static int mYTileCount;//Y轴上方格的个数

    private static int mXOffset;//绘图时X轴上的起始座标

 private static int mYOffset;//绘图时Y轴上的起始座标

private Bitmap[] mTileArray;//位图数组

private int[][] mTileGrid;//映射整个游戏画面的数组

private final Paint mPaint = new Paint();//画笔

mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);//设置方格的相对大小

public void resetTiles(int tilecount)//重置位图数组的长度

protected void onSizeChanged(int w, int h, int oldw, int oldh)//适应各种分辨率的屏幕

public void loadTile(int key, Drawable tile)//导入位图

public void clearTiles()//擦除游戏画面

public void setTile(int tileindex, int x, int y)//设置游戏画面:tileindex取值为01230:空白;1:redstar.png;2:yellowstar.png;3:greenstar.png.

public void onDraw(Canvas canvas)//根据mTileGrid数组绘制游戏画面

    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);

                   /**自己改的代码,将不同的位图替换为相应颜色的圆形*/

                 switch(mTileGrid[x][y]){               

                 case 1:mPaint.setColor(Color.RED);break;

                 case 2:mPaint.setColor(Color.YELLOW);break;

                 case 3:mPaint.setColor(Color.GREEN);                

                 }

                    canvas.drawCircle(mXOffset + x * mTileSize + mTileSize/2, mYOffset + y * mTileSize + mTileSize/2,

mTileSize/2, mPaint);

                }

            }

         }

 }

不同的界面

3. SnakeView.java

SnakeView的基类是TileView,是整个贪吃蛇游戏的核心,包含了游戏的算法及相应的数据。

    贪吃蛇移动的算法很简单,使用一个队列保存贪吃蛇身体的每一个节点的座标,移动时只需要根据移动的方向在队列的头部加入一个新的节点,同时删除尾部的节点。

    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++;

        }//标记头部

    }

    随机生成苹果的算法:随机生成苹果依赖随机函数Random();算法流程是先随机生成一个在(1,1)~(mXtileCount,mYtileCount)范围之内的座标,然后读取保存有贪吃蛇身体节点座标的队列,以保证生成的座标不在蛇的身体上。

    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为真,重新生成座标

                }

            }

            found = !collision;

        }

        if (newCoord == null) {

            Log.e(TAG"Somehow ended up with a null newCoord!");

        }

        mAppleList.add(newCoord);

    }

    处理按键事件:这一部分主要分为两个小部分;第一部分是处理游戏的开始及重新开始的按键事件;第二部分是处理在游戏过程中的按键事件。第二部分主要是通过前一移动方向(mDirection)和按键方向(KeyEvent),推出下一个移动方向(mNextDirection),主要是过滤掉和mDirection相反的方向。

    定时刷新游戏画面:定时刷新游戏画面通过android.os.handler类实现;

    class RefreshHandler extends Handler {

        @Override

        /**收到消息就执行的动作*/

        public void handleMessage(Message msg) {

            SnakeView.this.update();//计算一帧画面

            SnakeView.this.invalidate();//更新画面;调用Draw()

        }

        /**定时发消息*/

        public void sleep(long delayMillis) {

            this.removeMessages(0);

            sendMessageDelayed(obtainMessage(0), delayMillis);

        }

     };

4. View Hiersrchy

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章