南香园早夜茶 发表于 2023-1-2 09:36:51

canvas实现贪食蛇的实践

贪食蛇

最近 dan 有在油管上直播,播放量最多的就是手写一个贪食蛇。本来想学一下大佬写代码的姿势,看了几分钟就没了耐性,心想我为什么不能自己写一个呢。一步一步跟着敲代码,我实践了一段时间但是收效甚微,因为中间少了自己的思考。初期可能有些作用,可以学到一些技巧和规范。但是自己实现一个东西带来的成就感,你不断的 debug 和查文档查资料留下的记忆和习惯,这大概就是这个玩意带给我最大的收获吧。https://img.jbzj.com/file_images/article/202202/2022214162919161.gif?2022114163017在线演示github我的 github 一直是单机模式,如果这篇文章对您有所帮助的话欢迎点个 star数据结构及变量

const canvas = document.getElementById("canvas")
const ctx = canvas.getContext("2d")

const width = 400
const height = 400
const cellLength = 20

let foodPosition

let initSnake = [
,
,
,
]

let snake = [...initSnake]

let direction = "right"

let canChangeDirection = truecanvas 绘制页面

//背景
function drawBackground() {
ctx.strokeStyle = "#bfbfbf"
for (let i = 0; i <= height / cellLength; i++) {
    ctx.beginPath()
    ctx.moveTo(0, cellLength * i)
    ctx.lineTo(width, cellLength * i)
    ctx.stroke()
}

for (let i = 0; i <= width / cellLength; i++) {
    ctx.beginPath()
    ctx.moveTo(cellLength * i, 0)
    ctx.lineTo(cellLength * i, height)
    ctx.stroke()
}
}

// 蛇
function drawSnake() {
let step = 100 / (snake.length - 1)
for (let i = 0; i < snake.length; i++) {
    // 这里做了渐变色的蛇,添加动态色彩。尾部有个最小白色阀值,免得跟背景混为一体
    const percent = Math.min(100 - step * i, 90)
    ctx.fillStyle = `hsl(0,0%,${percent}%)`

    ctx.fillRect(
      snake * cellLength,
      snake * cellLength,
      cellLength,
      cellLength
    )
}
}

// 绘制食物

// 随机生成食物的位置
function generateRandomFood() {
// 如果没有位置可以生成
if (snake.length > width * height) {
    return alert("you win")
}
const randomX = Math.floor(Math.random() * (width / cellLength))
const randomY = Math.floor(Math.random() * (height / cellLength))
// 生成的位置如果跟蛇体积碰撞,则重新生成。
for (let i = 0; i < snake.length; i++) {
    if (snake === randomX && snake === randomY) {
      return generateRandomFood()
    }
}
foodPosition =
}

// 绘制
function drawFood() {
ctx.fillStyle = "#ff7875"
ctx.fillRect(
    foodPosition * cellLength,
    foodPosition * cellLength,
    cellLength,
    cellLength
)
}蛇的移动

// 蛇的移动
// 确定下一次移动的位置,将这个点push到数组末尾(头的位置),
// 将数组第一项shift出来(尾的位置)

// 吃食物的逻辑
// 如果食物的位置跟下一次移动的位置相同,将这个点加入头部,不推出尾部

function snakeMove() {
let next
let last = snake
// 根据方向确定下一个蛇头的位置
switch (direction) {
    case "up": {
      next = , last - 1]
      break
    }
    case "down": {
      next = , last + 1]
      break
    }
    case "left": {
      next = - 1, last]
      break
    }
    case "right": {
      next = + 1, last]
      break
    }
}

// 边缘碰撞
const boundary =
    next < 0 ||
    next >= width / cellLength ||
    next < 0 ||
    next >= height / cellLength

// 自身碰撞
const selfCollision = snake.some(() => next === x && next === y)

// 碰撞重新开始游戏
if (boundary || selfCollision) {
    return restart()
}

snake.push(next)

// 如果下一个点是食物的位置,不推出头部
if (next === foodPosition && next === foodPosition) {
    generateRandomFood()
    return
}
snake.shift()

canChangeDirection = true
}事件监听

document.addEventListener("keydown", (e) => {
switch (e.key) {
    case "ArrowUp":
      if (direction === "down" || !canChangeDirection) return
      direction = "up"
      canChangeDirection = false
      break
    case "ArrowDown":
      if (direction === "up" || !canChangeDirection) return
      direction = "down"
      canChangeDirection = false
      break
    case "ArrowLeft":
      if (direction === "right" || !canChangeDirection) return
      direction = "left"
      canChangeDirection = false
      break
    case "ArrowRight":
      if (direction === "left" || !canChangeDirection) return
      direction = "right"
      canChangeDirection = false
      break
}
})requestAnimationFrame 实现动画

// 默认的requestAnimationFrame循环应该是60帧,对于这个游戏来说太快了。
// 所以做了限制,5次loop才渲染(蛇移动一格)一次
function animate() {
let count = 0
function loop() {
    if (++count > 5) {
      draw()
      count = 0
    }
    requestAnimationFrame(loop)
}
requestAnimationFrame(loop)
}BUG 解决

游戏规则中,蛇是不能反向移动的。但是在事件回调中,如果改变方向过快,(5 次 loop 才执行一次重绘),就会出现方向变了,但是蛇的位置没变(比如蛇向右移动,我们先按上再按左),他就和自身碰撞了解决方案:我加了一个 canChangeDirection 变量,当你改变方向之后,必须等待蛇移动了才能再次改变方向// 事件回调
case "ArrowUp":
if (direction === "down" |!canChangeDirection) return
direction = "up"
canChangeDirection = false
break到此这篇关于canvas实现贪食蛇的实践的文章就介绍到这了,更多相关 canvas贪食蛇内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/html5/810952.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: canvas实现贪食蛇的实践