一份Canvas实现的贪吃蛇小游戏

2025/04/12

预览地址

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      http-equiv="X-UA-Compatible"
      content="IE=edge"
    />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0"
    />
    <title>Document</title>
    <style>
      #canvas {
        background-color: grey;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <script>
      // 定义游戏的尺寸
      const width = 400
      const height = 400
      const cellSize = 20

      // 定义贪吃蛇的方向
      const directions = {
        LEFT: { x: -1, y: 0 },
        RIGHT: { x: 1, y: 0 },
        UP: { x: 0, y: -1 },
        DOWN: { x: 0, y: 1 }
      }

      // 初始化 canvas 元素
      const canvas =
        document.getElementById('canvas')
      canvas.width = width
      canvas.height = height
      const ctx = canvas.getContext('2d')

      // 定义贪吃蛇的初始位置和方向
      let snake = [{ x: 0, y: 0 }]
      let direction = directions.RIGHT

      // 定义游戏的状态
      let isPlaying = false
      let score = 0

      // 定义食物的位置
      let food = { x: 0, y: 0 }

      // 在指定位置绘制一个正方形
      function drawCell(x, y) {
        ctx.beginPath()
        ctx.rect(
          x * cellSize,
          y * cellSize,
          cellSize,
          cellSize
        )
        ctx.fill()
      }

      // 绘制贪吃蛇
      function drawSnake() {
        snake.forEach((cell) =>
          drawCell(cell.x, cell.y)
        )
      }

      // 绘制食物
      function drawFood() {
        drawCell(food.x, food.y)
      }

      // 随机生成一个食物
      function generateFood() {
        food.x = Math.floor(
          Math.random() * (width / cellSize)
        )
        food.y = Math.floor(
          Math.random() * (height / cellSize)
        )
      }

      // 检查贪吃蛇是否吃到食物
      function checkFood() {
        if (
          snake[0].x === food.x &&
          snake[0].y === food.y
        ) {
          score++
          snake.push({
            ...snake[snake.length - 1]
          })
          generateFood()
        }
      }
      // 更新贪吃蛇的位置
      function updateSnake() {
        const head = { ...snake[0] }

        head.x += direction.x
        head.y += direction.y

        // 检查贪吃蛇是否碰到了边界
        if (
          head.x < 0 ||
          head.y < 0 ||
          head.x >= width / cellSize ||
          head.y >= height / cellSize
        ) {
          // 如果碰到了边界,游戏结束
          isPlaying = false
          return
        }

        // 检查贪吃蛇是否碰到了自己
        if (
          snake
            .slice(1)
            .some(
              (cell) =>
                cell.x === head.x &&
                cell.y === head.y
            )
        ) {
          // 如果碰到了自己,游戏结束
          isPlaying = false
          return
        }

        // 更新贪吃蛇的位置
        snake.unshift(head)
        snake.pop()
      }

      // 绘制游戏画面
      function draw() {
        // 清空画布
        ctx.clearRect(0, 0, width, height)

        // 绘制贪吃蛇
        drawSnake()

        // 绘制食物
        drawFood()
      }

      // 游戏的主循环
      function tick() {
        if (isPlaying) {
          updateSnake()
          checkFood()
          console.log(12)
          draw()
        } else {
          alert('game over')
          return
        }
        //   requestAnimationFrame(tick);
        setTimeout(tick, 500)
      }

      // 初始化游戏
      function init() {
        generateFood()
        isPlaying = true
        tick()
      }

      // 监听键盘事件,更新贪吃蛇的方向
      document.addEventListener(
        'keydown',
        (event) => {
          console.log(event.key)
          switch (event.key) {
            case 'ArrowUp':
            case 'w':
              direction = directions.UP
              break
            case 'ArrowDown':
            case 's':
              direction = directions.DOWN
              break
            case 'ArrowLeft':
            case 'a':
              direction = directions.LEFT
              break
            case 'ArrowRight':
            case 'd':
              direction = directions.RIGHT
              break
          }
        }
      )

      // 开始游戏
      init()
    </script>
  </body>
</html>

Post Directory