Android贪吃蛇游戏

闲来无事,就自己做了一个经典的贪吃蛇的小游戏,瞬间回到童年,感觉自己从头到尾写一个非常有意思。

演示效果

Github代码地址

实现步骤:

1.创建SceneView,将所需属性设计出来
2.绘制全盘的小方格,绘制蛇条,和初始食物
3.开线程让蛇移动起来
4.判断蛇吃到食物,再随机生成食物,蛇新增节点
5.判断边界

步骤代码讲解:

创建SceneView

创建SceneView,这里是游戏场景所需的属性。其中,用snakeList来存蛇的各个节点,用foodPos来表示食物的节点。由于手机比例是9:16,那么在横屏的方向下,我就将手机分为18行,行用j表示,32列,列用i表示,画18x32的小方格。每个节点用一个int值来表示,那么任何一格可以用j*100+i的int值来表示。

private var snakePaint: Paint = Paint()
    var blankPaint: Paint = Paint()
    var horizontalSpace: Float = 0f
    /** 方格间距 */
    private var dividerSpace = 3f
    /** 蛇的路径坐标记录 */
    private var snakeList = ArrayList<Int>()
    /** 食物的坐标位置 */
    var foodPos = 0
    /** 当前运动的方向 */
    var direction: Direction = Direction.RIGHT
    var timer: Timer? = null
绘制蛇条,和初始食物

先画第一行的32个各自,再遍历各行画完18行的格子。如果蛇或者食物的值在当前画的格子里,则画黑色,否则画灰色。

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        //画16*32的方格,而且有间距
        //画16行
        var curPaint: Paint
        for (j in 0..17) {
            //画每一行矩形
            for (i in 0..31) {
                if (snakeList.contains(j*100+i) || foodPos == (j*100+i)) {
                    //当前格在蛇的记录范围里,需要使用snakePaint
                    curPaint = snakePaint
                } else {
                    //使用blankPaint
                    curPaint = blankPaint
                }
                canvas.drawRect(i*(horizontalSpace+dividerSpace) + dividerSpace, j*(horizontalSpace+dividerSpace) + dividerSpace,
                    i*(horizontalSpace+dividerSpace) + dividerSpace + horizontalSpace,
                    j*(horizontalSpace+dividerSpace) + dividerSpace + horizontalSpace, curPaint)
            }
        }
    }
开线程让蛇移动起来

开启Timer,进行移动判断。首先获取头节点,根据方向,将下一个节点值添加到snakeList中,然后将尾节点删除。

    /**
     * 开始游戏
     */
    fun startGame() {
        timer = Timer()
        timer?.schedule(object: TimerTask() {
            override fun run() {
                move()
                invalidate()
            }

        }, 1000, 400)
    }

    /**
     * 继续移动
     */
    fun move() {
        if (addHead()) {
            restartGame()
            return
        }

        removeTail()
        handleFood()
    }

    /**
     * 添加头节点
     * 返回是否需要重新开始游戏
     */
    private fun addHead(): Boolean {
        var head = snakeList[snakeList.size-1]  //头结点位置
        //横左边移动+-1,纵坐标移动+-100
        //根据当前方向,将蛇移动
        when(direction) {
            //移动过程中,需要判断是否超出屏幕
            Direction.TOP -> {
                //如果头在第一行,还是向上,那么就失败了
                if (head < 100) {
                    //在第一行
                    return true
                } else {
                    snakeList.add(head-100)
                }
            }
            Direction.RIGHT -> {
                if (head % 100 == 31) {
                    //在最右一列
                    return true
                } else {
                    snakeList.add(head+1)
                }
            }
            Direction.DOWN -> {
                if (head >= 1700) {
                    //在最后一行
                    return true
                } else {
                    snakeList.add(head+100)
                }
            }
            Direction.LEFT -> {
                if (head % 100 == 0) {
                    //在最左一列
                    return true
                } else {
                    snakeList.add(head-1)
                }
            }
        }
        return false
    }

    /**
     * 删除尾节点
     */
    private fun removeTail() {
        //往当前方向移动一步,头往前一步,需要删除尾节点
        if (snakeList.size > 0) {
            snakeList.remove(snakeList[0])
        }
    }

判断蛇吃到食物,再随机生成食物,蛇新增节点

如果食物在蛇的节点值里面,那么就将foodPos在全盘方格中随机选取一个

    /**
     * 如果在蛇移动的过程中,包含了食物的位置,那么就吃掉了食物
     */
    private fun handleFood() {
        if (snakeList.contains(foodPos)) {
            //吃到了食物

            //从全盘面随机生成一个点数,且不再蛇的范围内,作为新生成食物
            foodPos = (Math.random()*18).toInt()*100 + (Math.random()*32).toInt()

            //蛇头节点长度+1
            addHead()
        }
    }

最后,判断边界,逻辑在上面addHead()方法中,判断方法是根据头节点的位置,判断根据当前方向,走下一步是否会超出,如头节点在第一行,如果方向向上,那么就超出边界了,此时,游戏应该重新开始。

重新开始游戏,初始化数据。

    /**
     * 重新开始游戏
     */
    private fun restartGame() {
        snakeList.clear()
        snakeList.add(0)
        snakeList.add(1)
        snakeList.add(2)
        foodPos = 13
        direction = Direction.RIGHT
    }

打完收工,如果需要完整代码的就戳上面Github地址。

推荐阅读更多精彩内容