赞
踩
html部分忽略,布局写的太辣眼了
用的表格td,利用双层for循环加上字符串的拼接,最终利用innnerHTML将布局显示
for (let i = 0; i < height; i++) {
str += '<tr>';
for (let j = 0; j < width; j++) {
if (i == 0) {
str += '<td>' + j + '</td>';
} else if (j == 0) {
str += '<td>' + i + '</td>';
} else {
str += '<td></td>';
}
}
str += '</tr>';
}
document.querySelector('table').innerHTML = str;
更改定时器的时间(简单)
let difficulty = document.querySelector("#difficulty");
difficulty.onchange = function () {
if (!isPlay) {
time = difficulty.value;
clearInterval(timeId);
difficulty.preventDefault();
}
}
利用一维数组存放蛇,但是因为需要确定蛇头和蛇身的位置需要横纵坐标,所以存放的是键值对形式的数据 {key_x: x_value , key_y: y_value}; ,如何显示蛇呢,道理和js实现动漫拼图1.0版中initEvent函数哪里说的的原理一样。snake一维数组记录的蛇身位置,移动场地是有n个tds组成的,通过snake记录的横纵坐标计算出对应的tds[index]中的index值(index=行×width+列)
,然后将这个td更换背景,来显示蛇。同理显示食物也是如此。
// 初始化蛇 function initSnake() { let snake = []; snake[0] = getRandom(); let x = snake[0].x; let y = snake[0].y; snake[1] = { x: x - 1, y: y }; snake[2] = { x: x - 2, y: y }; return snake; } //显示画面 function show(snake, food) { // 1 清除所有蛇和食物 tds.forEach(function (item) { item.style.backgroundColor = ''; }); // 2 显示蛇 snake.forEach(function (item, id) { let i = parseInt(item.x); let j = parseInt(item.y); console.log(i, j); let tdId = j * width + i; console.log(tdId); if (id == 0) { tds[tdId].style.backgroundColor = 'blue'; } else { tds[tdId].style.backgroundColor = 'green'; } }); // 3 显示食物 let tdFoodId = food.y * width + food.x; tds[tdFoodId].style.backgroundColor = 'red'; }
监听键盘的按键按下事件
通过按对应的wasd上左下右,来更改d的值,表示蛇头的移动方向,调用自己写的move函数,实现对应的行向或列向的加加减减实现上下移动,在配合上定时器,便实现了蛇的移动,但这是仅限于单个块的移动(蛇头),那其他块(蛇身)怎么正确随蛇身移动呢?(需要注意越界问题)
这里方法就很巧妙了,我们存放蛇用的是一维数组,而且一维数组有两个方法
pop:移除数组的尾部元素,并返回该值。
unshift:在数组头部添加新的元素。
思路:这里我们先不去考虑越界的情况,假设蛇头的下一个位置都是合法的。
首先,通过我们的按键事件,获得我们预使蛇头向那个方向移动,然后计算出新的蛇头,利用unshift将新蛇头加入snake数组,在利用pop移除最后面的一个(前面加一个,右面移除一个,这样就实现了蛇的移动,我们可以很容易想到整体一条直线的时候确实可以,那要是拐弯呢?也是可以的)
蛇在吃食物时,食物的位置肯定和新蛇头是重合,吃过食物之后蛇的长度应该加一,此时呢就只需要调用unshift函数,加入新蛇头就行了,不用移除后一个,在随机一个食物位置即可。
// 4.1 蛇的移动方向 document.addEventListener("keydown", direction); function direction(event) { if (event.keyCode == 65 && d != "RIGHT") { d = "LEFT"; } else if (event.keyCode == 87 && d != "DOWN") { d = "UP"; } else if (event.keyCode == 68 && d != "LEFT") { d = "RIGHT"; } else if (event.keyCode == 83 && d != "UP") { d = "DOWN"; } else if (event.keyCode == 32) { // 暂停 suspendGame(); } else if (event.keyCode == 82) { // 重新开始 restartGame(); } else if (event.keyCode == 66 && !isPlay) { // 开始 startGame(); } } // 4.2 蛇的移动 function move(snake) { let snakeX = snake[0].x; let snakeY = snake[0].y; let isEat = false; if (d == "LEFT") snakeX -= speed; if (d == "UP") snakeY -= speed; if (d == "RIGHT") snakeX += speed; if (d == "DOWN") snakeY += speed; if (snakeX == food.x && snakeY == food.y) { isEat = true; let tdId = food.y * width + food.x; tds[tdId].style.backgroundColor = 'lightgray'; score += 5; scoreSpan.innerHTML = score; food = getFood(snake); } let newHead = { x: snakeX, y: snakeY }; // 检测是否越界,或者自己碰到自己 if (snakeX < 0 || snakeX >= width || snakeY < 0 || snakeY >= height || collision(newHead, snake)) { endGame(); } else { // 没有吃到,移除最后一个,在头部加一个,蛇长不变 // 吃到,if不成立,蛇长不减,蛇头加一,整体变长一 if (!isEat) { snake.pop(); } snake.unshift(newHead); console.log("newHead=" + newHead.x + "," + newHead.y); }
越界问题
就是构造蛇头的时候,当前的蛇头如果已经处在上下左右某个边界了,肯定是不能在朝这个蛇头方向在移动了(这时候构造出来的新的蛇头的横纵坐标,肯定是不合法的,这里用的一维数组感觉不明显,下面的实现方法2,利用二维数组存储蛇时,这种情况,直接会索引越界报错的),而且根据游戏规则,出现越界问题时,也就是游戏结束之时(所谓的撞墙了)。所以呢,我们在产生新的蛇头坐标时,先去检查是否合法,确保不越界了,再去unshift加入数组首部,不然直接结束游戏;还有一种结束游戏,就是新的蛇头的位置,是在蛇的身体某个位置,就是自己碰自己,也直接结束游戏。
食物的随机位置不能在蛇身上
// 产生随机数字(游戏开始时蛇的随机位置和食物的随机位置) function getRandom() { // 蛇头的产生范围限定在(2-44) let ran_x = parseInt(Math.random() * (width - 4)) + 2; let ran_y = parseInt(Math.random() * height); return { x: ran_x, y: ran_y }; } // 检查食物随机产生的位置是否在蛇的身体上 function getFood(snake) { while (true) { let food = getRandom(); let flag = true; for (let i = 0; i < snake.length; i++) { let item = snake[i]; if (item.x == food.x && item.y == food.y) { flag = false; break; } } if (flag) { return food; } } }
其他就是一些繁琐的获取元素,添加事件,测试逻辑,该bug了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>贪吃蛇</title> <style> table { border-collapse: collapse; } .body { display: flex; height: 600px; background-color: lightblue; } td { border: 1px solid black; width: 15px; height: 15px; margin-left: 4px; font-size: 10px; } .print { flex: 70%; background-color: aliceblue; border: 1px solid red; width: 800px; } .content { margin: 0 auto; margin-top: 30px; width: 800px; background-color: lightgray; } .option { margin-top: 40px; flex: 20%; } .text1 { text-align: center; } button { margin-top: 10px; margin-bottom: 10px; width: 100px; height: 40px; background-color: orange; border: none; border-radius: 20px; } button:hover { background-color: yellow; } .snake, .snake1 { display: inline-block; width: 20px; height: 20px; background-color: blue; } .snake1 { background-color: green; } .food { display: inline-block; width: 20px; height: 20px; background-color: red; } .text2 { display: inline-block; width: 170px; font-size: 14px; width: 120px; } .bt { padding-left: 30px; box-sizing: border-box; } .score { text-align: center; } .score_span { display: block; margin-top: 5px; color: red; font-size: 30px; } select { margin-top: 10px; margin-bottom: 10px; width: 100px; height: 40px; background-color: lightcoral; border: none; text-align: center; border-radius: 20px; } .move span{ width: 20px; height: 20px; display: inline-block; border: 1px solid #000; color: black; background-color: white; box-shadow: 2px 2px #000; } .w{ margin-bottom: 2px; margin-right: 14%; } </style> </head> <body> <div class="body"> <div class="print"> <div class="content"> <table> </table> </div> </div> <div class="option"> <div class="text1"> 蛇:<span class="snake"></span><span class="snake1"></span><span class="snake1"></span> 食物:<span class="food"></span> </div> <div class="bt"> <span class="text2">按B键开始/继续:</span><button>开始游戏</button> </div> <div class="bt"> <span class="text2">按空格键暂停:</span> <button>暂停游戏</button> </div> <div class="bt"> <span class="text2">按R键重开:</span> <button>重新开始</button> </div> <div class="bt"> <span class="text2">游戏难度:</span> <select id="difficulty"> <option value="500">简单</option> <option value="300">一般</option> <option value="100">困难</option> <option value="50">噩梦</option> </select> <p style="color: red;">选择好难度后,按开始游戏(或B键)</p> </div> <div class="score"> 游戏得分 <span class="score_span">0</span> <div class="move"> 移动: <span class="w">W</span> <div> <span class="A">A</span> <span class="S">S</span> <span class="D">D</span> </div> </div> <p style="font-size: small;"> 说明:在游戏过程中更换游戏难度无效。<br> 若要更换难度:<br> 可在开始游戏前选择好难度<br> 或者暂停游戏选好难度后,再点击开始<br> 或者点击重新开始,然后选择难度后,再点击开始 </p> </div> </div> </div> <script> // 1 初始化场景 let str = ''; let width = 45; let height = 30; let isPlay = false; // 获取分数 let score = 0; let scoreSpan = document.querySelector('.score_span'); // 蛇的移动速度(定时器的时间) let timeId = 0; let time = 300; const speed = 1; let d = "RIGHT"; for (let i = 0; i < height; i++) { str += '<tr>'; for (let j = 0; j < width; j++) { if (i == 0) { str += '<td>' + j + '</td>'; } else if (j == 0) { str += '<td>' + i + '</td>'; } else { str += '<td></td>'; } } str += '</tr>'; } document.querySelector('table').innerHTML = str; let difficulty = document.querySelector("#difficulty"); difficulty.onchange = function () { if (!isPlay) { time = difficulty.value; clearInterval(timeId); difficulty.preventDefault(); } } // 2 初始化蛇 let snake = initSnake(); // 3 初始化食物,食物产生的随机位置不要在蛇身上 let food = getFood(snake); // 获取按钮 let bt = document.querySelectorAll('button'); // 获取所有td let tds = document.querySelectorAll('td'); bt[0].onclick = startGame; bt[1].onclick = suspendGame; bt[2].onclick = restartGame; // 初始化 show(snake, food); // 4 蛇的移动 // 4.1 蛇的移动方向 document.addEventListener("keydown", direction); function direction(event) { if (event.keyCode == 65 && d != "RIGHT") { d = "LEFT"; } else if (event.keyCode == 87 && d != "DOWN") { d = "UP"; } else if (event.keyCode == 68 && d != "LEFT") { d = "RIGHT"; } else if (event.keyCode == 83 && d != "UP") { d = "DOWN"; } else if (event.keyCode == 32) { // 暂停 suspendGame(); } else if (event.keyCode == 82) { // 重新开始 restartGame(); } else if (event.keyCode == 66 && !isPlay) { // 开始 startGame(); } } // 4.2 蛇的移动 function move(snake) { let snakeX = snake[0].x; let snakeY = snake[0].y; let isEat = false; if (d == "LEFT") snakeX -= speed; if (d == "UP") snakeY -= speed; if (d == "RIGHT") snakeX += speed; if (d == "DOWN") snakeY += speed; if (snakeX == food.x && snakeY == food.y) { isEat = true; let tdId = food.y * width + food.x; tds[tdId].style.backgroundColor = 'lightgray'; score += 5; scoreSpan.innerHTML = score; food = getFood(snake); } let newHead = { x: snakeX, y: snakeY }; // 检测是否越界,或者自己碰到自己 if (snakeX < 0 || snakeX >= width || snakeY < 0 || snakeY >= height || collision(newHead, snake)) { endGame(); } else { // 没有吃到,移除最后一个,在头部加一个,蛇长不变 // 吃到,if不成立,蛇长不减,蛇头加一,整体变长一 if (!isEat) { snake.pop(); } snake.unshift(newHead); console.log("newHead=" + newHead.x + "," + newHead.y); } } //显示画面 function show(snake, food) { // 1 清除所有蛇和食物 tds.forEach(function (item) { item.style.backgroundColor = ''; }); // 2 显示蛇 snake.forEach(function (item, id) { let i = parseInt(item.x); let j = parseInt(item.y); console.log(i, j); let tdId = j * width + i; console.log(tdId); if (id == 0) { tds[tdId].style.backgroundColor = 'blue'; } else { tds[tdId].style.backgroundColor = 'green'; } }); // 3 显示食物 let tdFoodId = food.y * width + food.x; tds[tdFoodId].style.backgroundColor = 'red'; } // TODO 功能按钮的实现 // 开始游戏 function startGame() { // clearInterval(timeId); isPlay = true; time = difficulty.value; timeId = setInterval(() => { move(snake); show(snake, food); }, time) } // 游戏结束 function endGame() { clearInterval(timeId); isPlay = false; alert("游戏结束"); } // 暂停游戏 function suspendGame() { if (isPlay) { clearInterval(timeId); isPlay = false; alert("游戏暂停"); } } // 重新开始 function restartGame() { // 关闭之前的定时器 clearInterval(timeId); score = 0; scoreSpan.innerHTML = score; snake = initSnake(); timeId = 0; time = 300; d = 'RIGHT'; isPlay = false; food = getFood(snake); show(snake, food); } // 产生随机数字(游戏开始时蛇的随机位置和食物的随机位置) function getRandom() { // 蛇头的产生范围限定在(2-44) let ran_x = parseInt(Math.random() * (width - 4)) + 2; let ran_y = parseInt(Math.random() * height); return { x: ran_x, y: ran_y }; } // 检查食物随机产生的位置是否在蛇的身体上 function getFood(snake) { while (true) { let food = getRandom(); let flag = true; for (let i = 0; i < snake.length; i++) { let item = snake[i]; if (item.x == food.x && item.y == food.y) { flag = false; break; } } if (flag) { return food; } } } // 初始化蛇 function initSnake() { let snake = []; snake[0] = getRandom(); let x = snake[0].x; let y = snake[0].y; snake[1] = { x: x - 1, y: y }; snake[2] = { x: x - 2, y: y }; return snake; } // 检查是否碰到自己 function collision(head, array) { for (let i = 0; i < array.length; i++) { if (head.x == array[i].x && head.y == array[i].y) { return true; } } return false; } </script> </body> </html>
完全不同的想法,很考验逻辑思维哟,做好准备
没有做很好的美化,只是实现功能
这里蛇的存储是借助了二维数组,利用二维数组的行列情况来记录位置,达到方式一中的直接在一维数组中记录{x,y}的效果;然后在二维数组里面全部初始化为undefined(其他的<0的值也行,主要是一种初始化标记),为甚小于0呢?因为这里我们给会在后面给二维数组里面赋值(0代表食物,1到n代表蛇,1是蛇头,后面紧邻的2,3,4,…n是蛇身)
显示的时候,就是普通的遍历二维数组获取里面的值,做不同的处理,更换背景色。
function show() { snake.forEach((subArr, i) => { subArr.forEach((s, j) => { let index = i * width + j; if (s == undefined) {//未定义的就是普通的td tds[index].style.backgroundColor = ''; } else if (s == 0) {//食物 tds[index].style.backgroundColor = 'red'; } else { if (s == 1) {//蛇头 tds[index].style.backgroundColor = 'black'; } else {//蛇身 tds[index].style.backgroundColor = 'green'; } } }) }) }
重难点
)
与上面的完全不同,上面有点取巧了,这里的考验思维了哟!
不用多说,首先肯定是去监听键盘,获取移动方向,根据不同的方向,构造出新的蛇头位置。这里构造出的新的蛇头和上面一样也要考虑越界情况(同上面)。下面我们默认新蛇头都是合法的,那么如何实现移动呢?交换
我们把新的蛇头称作
目标点
,把当前的蛇头称为原始点
,用两个变量nextX和nextY来记录新的蛇头的横纵坐标,用x0和y0来记录当前蛇头的坐标,我们就是通过有限次数(蛇长度)的交换记录蛇的二维数组的snake[x0][y0] 和snake[nextX][nextY]里面的值,来实现蛇的移动的,当然并没这么简单(我们之前说了蛇头处存的值是1,蛇身上存的值是2-n,这还没用到的呢!)
先来个简单的示例:(右移,图中标错了)
通过上述我们可以知道,我们用的nextX和nextY的值和x0和y0的值,肯定是动态变化的,如何变?
显然:第一步的移动中(蛇头的移动)nextX和nextY的值记录的就是新蛇头的位置坐标,在后面的过程中,nextX和nextY的值就是前一次交换过程中原始块的值(比如,蛇头前移一下,原始蛇头的位置,就是下一个原始块的目标位【用目标块记录】)。
整体在一条线上时,我们都好理解。
那么问题来了? 要是蛇身盘踞呢?还有就是我们通过for循环控制交换实现蛇的移动,我们每次循环多少次呢?
先说简单的,交换多少次,我们定义一个变量用来记录蛇长,for循环的次数就是当前蛇的长度(蛇头蛇身都要和目标块交换)。
再来说这个最不好想的,就是蛇的转向和盘踞移动,这里就用到了我们前面给蛇身上的标号,看下图详解。
(右移,图中标错了)
找寻标号,我们只需要找寻上一个原始块所处位置的下左右四个方位的即可。
当然找的时候也要注意到越界的情况:上下越界:
我们定义的snake是一维数组,在初始化时,动态的给他添加行(里面放一维的数组),在再一维里面放undefined,这样构成的二维数组,这样当我们上下找寻标号的时候,就可能出现arr[i][j] 中i
的索引值的越界情况,这个时候找寻的arr[i]是undefined,我们在去找arr[i][j],就是去找undefined中的j
位置的值,肯定是语法错误的,会报错,这时我们就需要对这种情况做处理。
左右越界:
这种情况是,我们找的i
索引肯定是不会出现越界的,但是j
可能会越界。但是呢,这时就算越界了,我们arr[i][j]的结果最多就是得到一个undefined,然而这并没什么大的影响,所以这里我们就不处理了。
// 根据方向做不同的操作 let nextX, nextY; if (direction == 37) { // 左 nextX = snakeHeadX; nextY = snakeHeadY - 1; } else if (direction == 38) { // 上 nextX = snakeHeadX - 1; nextY = snakeHeadY; } else if (direction == 39) { // 右 nextX = snakeHeadX; nextY = snakeHeadY + 1; } else if (direction == 40) { // 下 nextX = snakeHeadX + 1; nextY = snakeHeadY; } // 判断游戏结束 if (nextX >= height || nextX < 0 || nextY >= width || nextY < 0 || snake[nextX][nextY] > 0) { clearInterval(timeId); alert("游戏结束"); return; } // 原点记录每一个蛇身小格的前一个 let x0 = snakeHeadX; let y0 = snakeHeadY; // 记录新的蛇头 snakeHeadX = nextX; snakeHeadY = nextY; for (let i = 1; i <= snakeLength; i++) { let temp = snake[x0][y0]; snake[x0][y0] = snake[nextX][nextY]; snake[nextX][nextY] = temp; // 蛇身交换后,原点记录的蛇身小格的前一个,就是蛇身下个小格要前移的目标 nextX = x0; nextY = y0; // 查找上下左右四个方位,看snake二维数组中的值,是不是上面刚交换的下一个值(在蛇身上放的数值1,2,3...) // 向上找 if ((nextX - 1) > -1 && snake[nextX - 1][nextY] == i + 1) { x0--; } // 向下找 if ((nextX + 1) < height && snake[nextX + 1][nextY] == i + 1) { x0++; } // 向左找 if (snake[nextX][nextY - 1] == i + 1) { y0--; } // 向右找 if (snake[nextX][nextY + 1] == i + 1) { y0++; } }
这里不同于上面的方法一。同样,当新蛇头的位置与食物的位置重合时(食物身上的值为0),说明吃到食物,我们将记录蛇长的变量+1,同时在完成最后一次交换后x0和y0的值,就是之前蛇的尾部的位置,我们将这个位置在二维数组中做上标号(上边提到的2-n的标号),这也就是新的蛇尾,然后在随机一个食物位置即可。
当然这里随机食物,和之前的想法一样,不能随机到蛇身上,而我们给存放蛇的二维数组做了初始化,除了蛇之外都是undefined,当随机的位置是undefined时,就说明不在蛇身上。
if (snake[x0][y0] == 0) {
snake[x0][y0] = snakeLength + 1;
snakeLength++;
randomFood();
}
其他的就没什么了,就是绑定事件,测试调整逻辑
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } td { border: 1px solid #000; width: 20px; height: 20px; font-size: 13px; } .div1 { background-color: lightblue; height: 30px; padding-top: 5px; padding-left: 30px; box-sizing: border-box; } </style> </head> <body> <div class="div1"> <button id="start">开始游戏</button> <button id="stop">暂停游戏</button> 难度等级 <select id="select"> <option value="500">简单</option> <option value="300">一般</option> <option value="100">困难</option> <option value="40">噩梦</option> </select> 场地大小 <select id="size"> <option value="15">15x15</option> <option value="29">29x29</option> <option value="35">35x29</option> <option value="50">50x29</option> <option value="60">60x29</option> </select> </div> <div class="div2"> <table> </table> </div> <script> let tableContent = ''; let width; let height = 29; let snake = []; let timeId = 0; let time = 500; let table = document.querySelector('table'); let snakeLength; let direction; let tds; let snakeHeadX; let snakeHeadY; let isStop = false; let isPlay = false; let select = document.querySelector('#select'); select.onchange = function () { time = this.value; } let sizeSelect = document.querySelector('#size'); sizeSelect.onchange = function () { width = this.value; } window.onkeyup = function (e) { // 左37 上38 右39 下40 if (e.keyCode >= 37 && e.keyCode <= 40) { if (((direction == 37 || direction == 39) && (e.keyCode == 38 || e.keyCode == 40)) || ((direction == 38 || direction == 40) && (e.keyCode == 37 || e.keyCode == 39))) { direction = e.keyCode; } } } let startBtn = document.querySelector('#start'); startBtn.onclick = function () { clearInterval(timeId); tableContent = ''; snake = []; snakeLength = 2; direction = 39; initTable(); startGame(); randomFood(); if (!isPlay) { startBtn.innerHTML = '重新开始'; } else { startBtn.innerHTML = '开始游戏'; } isPlay = !isPlay; } let stopBtn = document.querySelector('#stop'); stopBtn.onclick = function () { if (!isStop) { clearInterval(timeId); stopBtn.innerHTML = '继续游戏'; } else { startGame(); stopBtn.innerHTML = '暂停游戏'; } isStop = !isStop; } function initTable() { width = sizeSelect.value; if(width==15) { height=15; }else{ height=29; } time = select.value; for (let i = 0; i < height; i++) { tableContent += '<tr>'; snake[i] = []; for (let j = 0; j < width; j++) { if (i == 0) { tableContent += '<td>' + j + '</td>'; } else if (j == 0) { tableContent += '<td>' + i + '</td>'; } else { tableContent += '<td></td>'; } snake[i][j] = undefined; } tableContent += '</tr>'; } table.innerHTML = tableContent; snakeHeadX = parseInt(height/2); snakeHeadY = parseInt(width/2); snake[snakeHeadX][snakeHeadY] = 1; snake[snakeHeadX][snakeHeadY - 1] = 2; tds = document.querySelectorAll('td'); } function show() { snake.forEach((subArr, i) => { subArr.forEach((s, j) => { let index = i * width + j; if (s == undefined) { tds[index].style.backgroundColor = ''; } else if (s == 0) { tds[index].style.backgroundColor = 'red'; } else { if (s == 1) { tds[index].style.backgroundColor = 'black'; } else { tds[index].style.backgroundColor = 'green'; } } }) }) } function startGame() { timeId = setInterval(() => { // 根据方向做不同的操作 let nextX, nextY; if (direction == 37) { // 左 nextX = snakeHeadX; nextY = snakeHeadY - 1; } else if (direction == 38) { // 上 nextX = snakeHeadX - 1; nextY = snakeHeadY; } else if (direction == 39) { // 右 nextX = snakeHeadX; nextY = snakeHeadY + 1; } else if (direction == 40) { // 下 nextX = snakeHeadX + 1; nextY = snakeHeadY; } // 判断游戏结束 if (nextX >= height || nextX < 0 || nextY >= width || nextY < 0 || snake[nextX][nextY] > 0) { clearInterval(timeId); alert("游戏结束"); return; } // 原点记录每一个蛇身小格的前一个 let x0 = snakeHeadX; let y0 = snakeHeadY; // 记录新的蛇头 snakeHeadX = nextX; snakeHeadY = nextY; for (let i = 1; i <= snakeLength; i++) { let temp = snake[x0][y0]; snake[x0][y0] = snake[nextX][nextY]; snake[nextX][nextY] = temp; // 蛇身交换后,原点记录的蛇身小格的前一个,就是蛇身下个小格要前移的目标 nextX = x0; nextY = y0; // 查找上下左右四个方位,看snake二维数组中的值,是不是上面刚交换的下一个值(在蛇身上放的数值1,2,3...) // 向上找 if ((nextX - 1) > -1 && snake[nextX - 1][nextY] == i + 1) { x0--; } // 向下找 if ((nextX + 1) < height && snake[nextX + 1][nextY] == i + 1) { x0++; } // 向左找 if (snake[nextX][nextY - 1] == i + 1) { y0--; } // 向右找 if (snake[nextX][nextY + 1] == i + 1) { y0++; } } if (snake[x0][y0] == 0) { snake[x0][y0] = snakeLength + 1; snakeLength++; randomFood(); } //显示蛇和食物 show(); }, time) } function randomFood() { while (true) { let x = Math.floor(Math.random() * height); let y = Math.floor(Math.random() * width); console.log(x, y); if (snake[x][y] == undefined) { snake[x][y] = 0; break; } } } </script> </body> </html>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。