闲来无事,就自己做了一个经典的贪吃蛇的小游戏,瞬间回到童年,感觉自己从头到尾写一个非常有意思。
演示效果
实现步骤:
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地址。