这个贪吃蛇玩起来头会晕...

无聊,搞个反人类的贪吃蛇玩玩吧…

准备

  1. 完成这个小小的游戏,仅使用了腾讯的MMKV(用于记录历史最高分)依赖,当然,不想导入依赖也可以使用原生的SharedPreferences进行替代。
  2. 关于icon,我在iconfont找到了自己喜欢的一个icon,当然,你也可以选择你喜欢的图标。

开始

绘制地图

贪吃蛇的移动是通过地图坐标的变化来修改蛇所在位置,绘制地图要把手机的屏幕像素转换成一个个小格子(坐标),同时需要考虑手机屏幕的大小不一问题,屏幕越大,地图格数越大,屏幕越小,则相反。

实现这样的需求,继承View时需要重写一个onSizeChanged(int w, int h, int oldw, int oldh)的方法,以此监听视图的大小发生变化时,设置地图格子的数量。

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)
    // 地图数据初始化
    tileCountX = Math.floor((w / tileSize).toDouble()).toInt()
    tileCountY = Math.floor((h / tileSize).toDouble()).toInt()
    // 够分成一格的分成一格, 剩下不够一格的分成两份,左边一份,右边一份
    startCoordinatesX = ((w - (tileSize * tileCountX)) / 2);
    startCoordinatesY = ((h - (tileSize * tileCountY)) / 2);
    tileImage = Array(tileCountX) { IntArray(tileCountY) }
    clearTiles()
}

绘制蛇

蛇的绘制与地图的绘制不同,且蛇是一个在地图上移动的个体,要继承于绘制地图的类,需要一个地图上的初始坐标(蛇的坐标,蛇出现的位置),初始的移动方向。

fun initSnake() {
    // 初始化蛇的初始位置
    snakeCoordinate.add(Coordinate(8, 7))
    snakeCoordinate.add(Coordinate(6, 7))
    snakeCoordinate.add(Coordinate(5, 7))
    snakeCoordinate.add(Coordinate(4, 7))
    // 设置蛇的初始移动方向
    directionCurrent = RIGHT
}

蛇的坐标设置好,还需要重写onDraw(canvas: Canvas?)方法绘制蛇的身体。

fun initSnakeBody() {
    //从文件中加载图片
    loadTile(SNAKE_Head, resources.getDrawable(R.drawable.head, resources.newTheme()))
    loadTile(SNAKE_BODY, resources.getDrawable(R.drawable.zongzi, resources.newTheme()))
    updateView()
}

fun loadTile(key: Int, drawable: Drawable) {
    val createBitmap = Bitmap.createBitmap(tileSize, tileSize, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(createBitmap)
    drawable.setBounds(0, 0, tileSize, tileSize)
    drawable.draw(canvas)
    tileBitmap!![key] = createBitmap
}

当蛇的位置发生变化、坐标更新,原有已绘制的界面需要跟着变化,要执行Viewinvalidate()方法请求废除原有的视图,重新进行绘制。

绘制蛇的食物

既然是贪吃蛇,少不了蛇的食物。作为蛇的食物,不能一直每次都在同一个位置生成,这就用到了Random类随机生成一个x轴、y轴随机数,两个数拼凑一起,就成了食物的坐标。事物也不能在蛇的当前所在坐标生成,在生成食物的时候还需加上判断新生成的食物是否与当前蛇的所在位置冲突了。

fun addRandomFood() {
    var newCoord: Coordinate? = null
    var found = false
    while (!found) {
        // 设置新食物生成的位置
        val newX: Int = random.nextInt(50)
        val newY: Int = random.nextInt(30)
        newCoord = Coordinate(newX, newY)
        var collision = false
        val snakelength: Int = snakeCoordinate.size
        //遍历snake, 看新添加的粽子是否与snake的所在坐标冲突,如果是,重新生成坐标
        for (index in 0 until snakelength) {
            if (snakeCoordinate[index].equals(newCoord)) {
                collision = true
            }
        }
        for (index in obstacleCoordinate.indices) {
            if (obstacleCoordinate[index].equals(newCoord)) {
                collision = true
            }
        }
        found = !collision
    }
    // 储存已产生坐标
    foodCoordinate.add(newCoord!!)
}

控制蛇的方向

贪吃蛇的移动轨迹只能是屏幕范围,当蛇头撞上屏幕的四条边界、自己的身体,即视为游戏失败,因此蛇的每一次移动,都需要去判断是否是撞上了墙、自己的身体、是否吃到了食物。

fun updateSnake() {
    // 检测投是否撞墙(屏幕的四个边)
    if (newHead.x!! < 0 || newHead.y!! < 0 || newHead.x!! > tileCountX - 1 || newHead.y!! > tileCountY - 1) {
        // 游戏结束
        return
    }
    // 检测头是否撞到自己
    val snakeSize = snakeCoordinate.size
    for (snakeindex in 0 until snakeSize) {
        val get = snakeCoordinate[snakeindex]
        if (get.equals(newHead)) {
            // 游戏结束
        }
    }
}

设计初期,有想过如果开发的贪吃蛇和他人开发的贪吃蛇相比较,至少应该有点创新。经过一番苦思冥想,发觉可在控制蛇的操作上做一点点小修改,只是这一改也没啥,可玩家一玩起来头就会晕…

在这里插入图片描述

具体有何区别?市面上的贪吃蛇操作方向一般都是使用遥感,或者上下左右的方向键来操作,为了我那一点点的与众不同,决定使用手机重力的方向来作为蛇的方向。

override fun setListener() {
    orientationEventListener =
        object : OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
            override fun onOrientationChanged(orientation: Int) {
                var orientation = orientation
                if (orientation == ORIENTATION_UNKNOWN) {
                    return  //手机平放时,检测不到有效的角度
                }
                // 检测是否有四个角度的改变
                orientation = if (orientation > 340 || orientation < 20) {
                    SnakeView.RIGHT
                } else if (orientation in 71..109) {
                    SnakeView.UP
                } else if (orientation in 161..199) {
                    SnakeView.LEFT
                } else if (orientation in 251..289) {
                    SnakeView.DOWN
                } else {
                    -1 // 无效方向
                }
                if (orientation != -1) {
                    // 设置蛇的下一个方向
                    if (orientation != directionCurrent) {
                        directionNext = orientation
                    }
                }
            }
        }
    // 启动手机侧重方向监听
    orientationEventListener!!.enable()
}

使用OrientationEventListener(Context context, int rate)监听手机重力方向,界面销毁时谨记该事件同时执行销毁,避免占用内存。

最终效果

表面上的贪吃蛇

在这里插入图片描述

实际上的贪吃蛇

在这里插入图片描述

完整代码

完整代码、Apk文件已上传至Gitee,点击前往查看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宾有为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值