先看看效果图
贪吃蛇设计思路 贪吃蛇分为3个对象:
舞台我们可以看作为一个二维数组 蛇和食物 都是数组中的元素
蛇是一串数组中的连续的元素 分为蛇的头元素和蛇身长度
食物可以看作是数组中的一个元素
蛇的移动 蛇可以向上,向下,向左,向右移动
蛇移动 头元素+1 尾元素-1
碰撞检测 当蛇的头部元素碰撞到食物 则吃掉食物 蛇长度+1。 如果碰撞到蛇身 游戏结束,到舞台边界 直接穿过去
随机生成食物 使用Random
生成食物坐标 x,和y 生成后判断是不是在蛇身坐标上,如果是重新生成。
代码实现 首先我们使用自定义View
来实现
1 2 3 4 5 6 7 8 public class SnakePanelView extends View { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制界面... } }
然后我们定义格子元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class GridSquare { private int mType;//元素类型 public GridSquare(int type) { mType = type; } public int getColor() { switch (mType) { case GameType.GRID://空格子 return Color.WHITE; case GameType.FOOD://食物 return Color.BLUE; case GameType.SNAKE://蛇 return Color.parseColor("#FF4081"); } return Color.WHITE; } public void setType(int type) { mType = type; } }
这个就是格子对象
然后我们定义出的二维数组舞台定义如下:
1 private List<List<GridSquare>> mGridSquare = new ArrayList<>();
定义出了舞台数组 我们需要定义食物的位置和蛇的位置。所以我们需要定义一个对象 这个对象需要两个成员变量 x
和 y
来标示在舞台中的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class GridPosition { private int x; private int y; public GridPosition(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
然后我们需要定义蛇头位置、蛇身List
和食物的位置
1 2 3 private List<GridPosition> mSnakePositions = new ArrayList<>(); private GridPosition mSnakeHeader;//蛇头部位置 private GridPosition mFoodPosition;//食物的位置
然后我们需要定义蛇的一系列属性:速度、蛇身长度和运动方向。
1 2 3 private int mSnakeLength = 3;//蛇身长度 private long mSpeed = 8;//运行速度 值越大 速度越快 private int mSnakeDirection = GameType.RIGHT;//运行方向
让蛇运动起来我们需要一个游戏主循环 我们可以简单定义一个循环
1 2 3 4 5 6 7 8 9 private class GameMainThread extends Thread { @Override public void run() { while (true) { //todo... } } }
我们在循环里处理蛇移动、碰撞检测和食物生产等操作。
处理蛇的移动方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 private void moveSnake(int snakeDirection) { switch (snakeDirection) { case GameType.LEFT: if (mSnakeHeader.getX() - 1 < 0) {//边界判断:如果到了最左边 让他穿过屏幕到最右边 mGridSize 为舞台大小 mSnakeHeader.setX(mGridSize - 1); } else { mSnakeHeader.setX(mSnakeHeader.getX() - 1); } mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY())); break; case GameType.TOP: if (mSnakeHeader.getY() - 1 < 0) { mSnakeHeader.setY(mGridSize - 1); } else { mSnakeHeader.setY(mSnakeHeader.getY() - 1); } mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY())); break; case GameType.RIGHT: if (mSnakeHeader.getX() + 1 >= mGridSize) { mSnakeHeader.setX(0); } else { mSnakeHeader.setX(mSnakeHeader.getX() + 1); } mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY())); break; case GameType.BOTTOM: if (mSnakeHeader.getY() + 1 >= mGridSize) { mSnakeHeader.setY(0); } else { mSnakeHeader.setY(mSnakeHeader.getY() + 1); } mSnakePositions.add(new GridPosition(mSnakeHeader.getX(), mSnakeHeader.getY())); break; } }
处理碰撞:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //检测碰撞 private void checkCollision() { //检测是否咬到自己 GridPosition headerPosition = mSnakePositions.get(mSnakePositions.size() - 1); for (int i = 0; i < mSnakePositions.size() - 2; i++) { GridPosition position = mSnakePositions.get(i); if (headerPosition.getX() == position.getX() && headerPosition.getY() == position.getY()) { //咬到自己 停止游戏 mIsEndGame = true; showMessageDialog(); return; } } //判断是否吃到食物 if (headerPosition.getX() == mFoodPosition.getX() && headerPosition.getY() == mFoodPosition.getY()) { mSnakeLength++; generateFood(); } }
随机生成食物:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void generateFood() { Random random = new Random(); int foodX = random.nextInt(mGridSize - 1); int foodY = random.nextInt(mGridSize - 1); for (int i = 0; i < mSnakePositions.size() - 1; i++) { if (foodX == mSnakePositions.get(i).getX() && foodY == mSnakePositions.get(i).getY()) { //不能生成在蛇身上 foodX = random.nextInt(mGridSize - 1); foodY = random.nextInt(mGridSize - 1); //重新循环 i = 0; } } mFoodPosition.setX(foodX); mFoodPosition.setY(foodY); refreshFood(mFoodPosition); }
基本的游戏逻辑已经完成。
工程已经放在GITHUb