Home  >  Article  >  Web Front-end  >  How to use Vue3+Canvas to implement a simple snake game

How to use Vue3+Canvas to implement a simple snake game

王林
王林forward
2023-05-12 21:58:041326browse

    How to use Vue3+Canvas to implement a simple snake game

    Rules

    How to play: The player uses the direction keys to control a long snake to continuously swallow beans. The body continues to grow as the beans are swallowed, and the game ends when the snake's head hits the snake's body or a barrier.

    Ideas

    Elements: boundary, snake head, snake body, food

    Boundary: Enter the number of rows x, the number of columns y to generate a boundary map, and use two-dimensional coordinates to identify each Point position;

    Snake head, snake body: The snake head and snake body are separated. When food is eaten, one is added to the tail of the snake body.

    Food: The position is randomly generated;

    Flow chart

    How to use Vue3+Canvas to implement a simple snake game

    Code implementation

    Technology stack

    Selectvue3, vite Infrastructure; View selectioncanvas technology to achieve better performance than dom;

    Basic variable definition

    <script setup lang="ts">
      import { ref, onMounted } from &#39;vue&#39;
      
      let width = ref(600) // 地图默认宽度
      let height = ref(400) // 地图默认高度
      let canvas: any = null // canvas 对象
      let ctx: any = null // canvas 渲染上下文对象
      let snakeList = [[0, 100], [10, 100],] // 蛇的点位坐标
      let direction = &#39;right&#39; // top | down | left | right // 当前方向
      let elementWidth = 10 // 元素尺寸
      let step = 10 // 速度
      let store = ref(0) // 分数
      let status = ref(&#39;start&#39;) // unStart | start | pause | over | success(通关) // 状态
      let foodCoordinate: any = [
        ((Math.random() * width.value) / 10) | 0,
        ((Math.random() * height.value) / 10) | 0,
      ] // 食物坐标
      let process: any = null // 定时器 Id
    </script>

    Initialization

    Executed in onMounted, mainly for map drawing , mouse coordinate detection, direction monitoring, food drawing, timer activation and other operations.

    function handleInit() {
      canvas = document.getElementById(&#39;canvas&#39;)
    
      if (canvas?.getContext) {
        ctx = canvas?.getContext(&#39;2d&#39;)
    
        canvas.addEventListener(&#39;mousemove&#39;, e => {
          ctx.clearRect(10, height.value - 20, 120, 40)
          ctx.fillText(`当前鼠标位置:${e.offsetX}, ${e.offsetY}`, 10, height.value - 10)
        })
    
        document.addEventListener(&#39;keydown&#39;, e => {
          e.preventDefault()
    
          if (Direction[e.keyCode]) {
            direction = Direction[e.keyCode]
          }
        })
    
        process = setInterval(handleRenderSnake, 150)
        handleRenderFood()
        // window.requestAnimationFrame(handleRenderSnake)
      } else {
        alert(&#39;您的浏览器不支持 canvas&#39;)
      }
    }

    Food drawing

    When food is eaten, it needs to be destroyed and regenerated

    // 绘制食物
    function handleRenderFood() {
      ctx.clearRect(foodCoordinate[0], foodCoordinate[1], 10, 10)
      foodCoordinate = [(Math.random() * width.value) | 0, (Math.random() * height.value) | 0]
      ctx.fillStyle = &#39;#eb2f96&#39;
      ctx.fillRect(foodCoordinate[0], foodCoordinate[1], 10, 10)
    }

    Snake head/snake body drawing

    Snake is two-dimensional Represented in an array, each node represents a part of the body, and the first node represents the snake's head. The movement of the snake is achieved by deleting the tail node and adding the head node. The middle node does not need to move, and the processing in the four directions is slightly different. Note that when food is eaten, the tail node of the current frame is no longer deleted, and the length of the snake body is increased by 1.

    function handleRenderSnake() {
      switch (direction) {
        case &#39;top&#39;:
          if (snakeList.slice(-1)[0][1] <= 0) {
            status.value = &#39;over&#39;
            return
          }
    
          snakeList.push([
            snakeList[snakeList.length - 1][0],
            snakeList[snakeList.length - 1][1] - step,
          ])
          handleUpdateVerify()
          break
        case &#39;down&#39;:
          if (snakeList.slice(-1)[0][1] >= height.value - 1) {
            status.value = &#39;over&#39;
            return
          }
    
          snakeList.push([
            snakeList[snakeList.length - 1][0],
            snakeList[snakeList.length - 1][1] + step,
          ])
          handleUpdateVerify()
    
          break
          ...

    Collision algorithm, boundary conditions

    When the snake head touches the edge of the map, the game will be over. You only need to calculate whether the next coordinates will exceed the map size based on the current coordinates and current direction of the snake head. That’s it.

    Calculation method of eating food: Calculate the absolute values ​​of the x and y axes of the snake head coordinates and food coordinates respectively. If it is smaller than the element size, it is considered to have been in contact.

    // 更新校验
    function handleUpdateVerify() {
      if (status.value === &#39;pause&#39;) {
        clearInterval(process)
      }
    
      if (store.value >= 100) {
        status.value = &#39;success&#39;
        return
      }
    
      for (let i of snakeList) {
        ctx.clearRect(i[0], i[1], elementWidth, elementWidth)
      }
    
      let currentSnake = snakeList.slice(-1)[0]
      if (
        Math.abs(currentSnake[0] - foodCoordinate[0]) < 10 &&
        Math.abs(currentSnake[1] - foodCoordinate[1]) < 10
      ) {
        store.value++
        handleRenderFood()
      } else {
        snakeList.shift()
      }
    }

    Points calculation, pause, continue and other functions

    The global variable status represents the status of the current situation. When status === 'pause', the pause operation is triggered, the timer variable is deleted, click Restart button to generate a new timer.

    When food is eaten, the global variable store is bidirectionally bound to the page for display. Temporarily set the score to exceed 100 to pass the level.

    The above is the detailed content of How to use Vue3+Canvas to implement a simple snake game. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete