Snake Rule:

Snake ends the game when its head touches a wall. Snake ends the game when its head touches its bodyCopy the code

Analysis:

Need a board, board will randomly generate 5 points (food), need a greedy snake, direction key control greedy snake movement direction. And most importantly, how does a snake move? Controlling DOM movement is difficult because snakes can bend at will and are hard to calculate. If you have an array of points on a checkerboard, let those points change color. That makes it easier. Each point on the board can have a regular coordinate, such as the first [0,0] in the first row and the second [0,1]..... (0, n), Second row first [1,0], second [1,1]...... (1, n), The first [n, 0], the second [n, 1]...... [n, n]; When the snake moves up, it makes the head x-1, when it moves down, it makes the head X-1, when it moves left, it makes the head y-1, and when it moves right, it makes the head Y-1. Each move adds a point to the snake array (unshift) and removes a point at the end (pop). When encountering food, add the coordinates of the food to the snake array, and increase the length of the snake; The game is over if the snake touches the wall or its own body.Copy the code

Code: index. Vue

<template> <div class="wrap"> <div class="shade" v-show="over || ! begin"> <div v-show="! Begin "class="bigText"> <span> Start </span> <div > <div v-show="over" class="bigText"> <div v-show="over" Class ="text-align-center"> The game ends </div> <br> <br> <span> Press the arrow key to restart </span> </div> </div> <div </div> <div class="grid-item" > <div class="grid-item" v-for="item,index in grid" :class="{snake:snake.includes(item.value), randomPoint: randomPoint.includes(item.value), special: status, over: over}" :key="index"> </div> </div> </div> </template> <script> import { defineComponent, ref } from 'vue' import { useGrid, genarateRandomPoint, interval } from './hooks/grid' export default defineComponent({ setup() { let speed = 500; let [ grid, snake, derection, status, over, begin, { bindEvents, changeStatus } ] = useGrid(); bindEvents(e => { console.log(begin.value, 'begin.value'); console.log(over.value, 'over.value'); if (! Begin. value) {console.log(' not started '); // If not, press the arrow key to begin begin.value = true; changeSpeed(speed); If (over. Value) {over. Value = false; speed = 500; Snake. Value = [' 15, 15 ']; Console. log(' restart '); changeSpeed(speed); // Initial speed 500 return; } switch( e.keyCode ) { case 37: if (derection.value ! = 'right') { derection.value = 'left'; } break; case 38: if (derection.value ! = 'bottom') { derection.value = 'top'; } break; case 39: if (derection.value ! = 'left') { derection.value = 'right'; } break; case 40: if (derection.value ! = 'top') { derection.value = 'bottom'; } break; default: break; } console.log(derection.value, 'derection.value'); }); Let randomPoint = ref(genarateRandomPoint(Grid, Snake, 5)); let { startInterval, stopInterval } = interval(); var changeSpeed = startInterval(() => { console.log(snake.value[0], 'snake.value[0]'); let nextGrid = { coordinate: snake.value[0].split(',').map(Number), value: snake.value[0] } let addArray = [1, 1]; switch(derection.value){ case 'left': console.log('left'); addArray = [0, -1]; break; case 'right': console.log('right'); addArray = [0, 1]; break; case 'top': console.log('top'); addArray = [-1, 0]; break; case 'bottom': console.log('bottom'); addArray = [1, 0]; break; } nextGrid.coordinate = [nextGrid.coordinate[0] + addArray[0], nextGrid.coordinate[1] + addArray[1]]; nextGrid.value = nextGrid.coordinate.join(','); console.log(nextGrid, 'nextGrid'); if (nextGrid.coordinate[0] > 29 || nextGrid.coordinate[1] > 29 || nextGrid.coordinate[0] < 0 || nextGrid.coordinate[1] < 0) {console.log(' hit the wall '); over.value = true; stopInterval(); return; } else if (snake.value.includes(nextgrid.value)) {console.log(' hit yourself '); over.value = true; stopInterval(); return; } / / touch food the if (randomPoint. Value. Includes (nextGrid. Value)) {let newPoint = randomPoint.value.splice(randomPoint.value.indexOf(nextGrid.value),1)[0]; snake.value.unshift(newPoint); changeStatus(); If (snake. Value. Length % 5 == 0) {speed -= 100; changeSpeed(speed) } if ( randomPoint.value.length < 1) { randomPoint.value = randomPoint.value.concat(genarateRandomPoint(grid, snake, 5)); } } else { snake.value.pop(); snake.value.unshift(nextGrid.value); }}); return { grid, snake, derection, status, over, begin, interval, randomPoint } }, }) </script> <style lang="scss" scoped> @keyframes color{ 0% { background:black; } 25% { background:red; } 50% { background:orange; } 75% { background:blue; } 100% { background:black; } } .text-align-center{ text-align: center; font-weight: bold; } .wrap{ position: relative; .shade{ position: absolute; top:0; left:0; bottom: 0; right:0; z-index: 1; background:rgba(#000, .6); display: flex; justify-content: center; align-items: center; .bigText{ color: white; font-size: 30px; letter-spacing: 3px; font-weight: bold; } } } .grid{ margin:20px auto; display: flex; flex-wrap: wrap; width:602px; border-top:1px solid black; border-left: 1px solid black; .grid-item{ box-sizing: border-box; flex-shrink: 0; border-right:1px solid black; border-bottom: 1px solid black; width:20px; height:20px; &.snake{ background:black; &.special{ animation: color .5s infinite; } &.over{ background:gray; } } &.randomPoint{ background:green; } } } </style>Copy the code

hooks/grid.js

Import {ref} from 'vue' export function useGrid(){let grid = ref([]); // mesh let snake = ref(['15,15']); // let derection = ref('top'); // let status = ref(false); // Let over = ref(false); // game over let begin = ref(false); New Array(30).fill(1).foreach ((xItem, x) => {new Array(30).fill(1).foreach ((yItem, x)) y) => { grid.value.push({ coordinate:[x, y], value:`${x},${y}` }) }) }); function bindEvents(cb){ document.addEventListener('keydown', e => { cb(e) }) } function destroyEvents(){ document.removeEventListener('keydown'); } function changeStatus(){status.value = true; setTimeout(() => { status.value = false; },2000) } return [ grid, snake, derection, status, over, begin, { bindEvents, destroyEvents, Export function genarateRandomPoint (grid, nake, count) {let arr = []; let createNumberArray = (grid, nake) => { let randomPoint = grid.value[Math.floor(Math.random() * 901)].value; while(nake.value.includes(randomPoint.value)){ randomPoint = grid.value[Math.floor(Math.random() * 901)].value; } return randomPoint; } new Array(count).fill(1).forEach(() => { arr.push(createNumberArray(grid, nake)); }); return arr; } // export function interval(){let timer = null; Function startInterval(cb){return function(speed){stopInterval(); timer = setInterval(() => { cb() }, speed); } } function stopInterval(){ clearInterval(timer); timer = null; } return { startInterval, stopInterval } }Copy the code