手势操作的Snake游戏_游戏逻辑分析

手势操作的Snake游戏_游戏逻辑分析

本文是snake on a phone 贪吃蛇游戏的项目解析系列文章之5,基于google sample code 改编而成项目链接接上一篇文章手势操作的Snake游戏_游戏视图分析之SnakeView

上一节我们对SnakeView框架进行了分析,本节对游戏逻辑细节进行解析,也就是对update中的具体细节分析。

update函数

public void update() {
    if (mMode == RUNNING) {
        long now = System.currentTimeMillis();

        if (now - mLastMove > mMoveDelay) {
            clearTiles();//所有网格归零
            updateWalls();//赋值墙壁 绿色标示
            updateSnake();//更新蛇的坐标
            updateApples();//更新苹果的坐标
            mLastMove = now;//记录最后一次运动时间
        }
        mRedrawHandler.sleep(mMoveDelay);
    }

}

主要逻辑在updateSnake和updateApples中。

相关参数

private ArrayList mSnakeTrail = new ArrayList();
private ArrayList mAppleList = new ArrayList();

mSnakeTrail表示蛇身的坐标集合,从头到尾。
mAppleList所有出现过的苹果的坐标,也就是被蛇吃过的位置。
游戏开始的时候我们对他们进行初始化

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

updateSnake()

更新蛇的时候,需要进行碰撞检测,一是和周围墙壁是否碰撞,二是和自身是否接触,然后再看是否吃到苹果,根据结果决定是否添加苹果,以及是否去掉蛇尾,以下代码在保持源示例代码的基础上加了自己的一些注释。
private void updateSnake() {
boolean growSnake = false;

    // grab the snake by the head
    //找到头部
    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;
    }
    }

    // Collision detection
    // For now we have a 1-square wall around the entire arena
    //碰撞检测、看是否和墙壁碰撞,碰撞则设定游戏失败
    if ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2)
            || (newHead.y > mYTileCount - 2)) {
        setMode(LOSE);
        return;

    }

    // Look for collisions with itself
    //判定蛇头有木有撞到自己,撞到则设定游戏失败
    int snakelength = mSnakeTrail.size();
    for (int snakeindex = 0; snakeindex < snakelength; snakeindex++) {
        Coordinate c = mSnakeTrail.get(snakeindex);
        if (c.equals(newHead)) {
            setMode(LOSE);
            return;
        }
    }

    // Look for apples
    //判断是否吃到苹果,吃到苹果则在苹果列表中移除对应苹果坐标,并随即生成添加一个新的苹果
    //吃掉苹果的设定growSnake标志true,在更新蛇的时候会用到
    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;
        }
    }

    // push a new head onto the ArrayList and pull off the tail
    //首先把新蛇头加上
    mSnakeTrail.add(0, newHead);
    // except if we want the snake to grow
    //如果growSnake不是true,说明没有吃到苹果,蛇身长度一定,加头则要去尾
    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++;
    }

}

updateApples()

由于在updateSnake中对苹果坐标集合mAppleList已经进行了数值更新,这里只需进行绘制即可。
private void updateApples() {
for (Coordinate c : mAppleList) {
setTile(YELLOW_STAR, c.x, c.y);
}
}

addRandomApple()

updateSnake中涉及到随机添加一个苹果坐标的情况(游戏初始化的时候也会随机添加两个苹果),利用了随机函数来生成。

private void addRandomApple() {
    Coordinate newCoord = null;
    boolean found = false;
    while (!found) {
        // Choose a new location for our apple
        //随机生成坐标,必须在墙内  nextInt表示[0,n)  newx-> [1,mXTileCount-1)
        int 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 snake
        boolean 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 again
        found = !collision;
    }
    if (newCoord == null) {
        Log.e(TAG, "Somehow ended up with a null newCoord!");
    }
    mAppleList.add(newCoord);
}

nextInt(a,b)函数生成的数值范围[a,b),所以newx-> [1,mXTileCount-1),坐标必须是墙内坐标。这里利用穷举的方式,随机生成一个苹果,判断是否和蛇重叠,直到找到合理的坐标为止。

思考

不清楚贪吃蛇游戏最后能够玩到什么程度,如果在addRandomApple中真的一个都找不到的话,蛇长应该等于x*y,有兴趣的可以去分析一下是什么场景,我们的update函数中对于刷新是有一个时间参数的,而且随着游戏进行,速度加快,游戏难度也加大。

你可能感兴趣的:(android,有趣的android开源项目)