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地址。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容