40行贪吃蛇 原生js

Posted migeater

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了40行贪吃蛇 原生js相关的知识,希望对你有一定的参考价值。

相比于网上很火的20行贪吃蛇,这个版本有 2000 个字符,刚好也是20行版本字符数的两倍

环境是ES6

相较于20行版本

  1. 此版本用的是二维坐标系,而不是一维,因此更好调试
  2. 代码可读性更强,尽管为了省行数,控制流看起来不正常,并且用了很多隐式的循环(虽说jQuery一共也就3行
  3. 修补了一个BUG: 蛇身长为4时,是不可能碰到自己的

40行版本

  1. <!doctype html>
  2. <html>
  3. <body>
  4. <canvas id="1" width="400" height="400" ></canvas>
  5. <script>
  6.     let ctx = document.getElementById("1").getContext("2d");
  7.     let SpecialLen = 20, snakeDir = 2, snakeDirNow , food = [2,0], snakeBody = [ [0, 0], [1, 0] ]; //2 for right direction
  8.     let Map = {}; //map对象存放 location:val ,‘1,2‘:1 ,1表示蛇身,2表示食物
  9.     for(let snakeNode of snakeBody) Map[snakeNode] = 1;
  10.     let dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]]; //0 1 2 3 <- ->
  11.     let pairEqual = ((pair1, pair2) => pair1[0] == pair2[0] && pair1[1] == pair2[1]); //碰撞检测
  12.     document.onkeydown = function (env) {
  13.         arrowKeyCode = env.keyCode - 37; //37"leftArrow"
  14.         if (0 <= arrowKeyCode == arrowKeyCode < 4) //忽视其他键
  15.             if (snakeDirNow !== (arrowKeyCode + 2) % 4) //周期过后才改变方向&&不能走相反方向
  16.                 snakeDir = arrowKeyCode;
  17.     };
  18.     !function () {
  19.         let snakeHeadNext = snakeBody[snakeBody.length-1].map((x, i) => x + dirMat[snakeDirNow=snakeDir][i]); //得到蛇头的下一步位置
  20.         if (!pairEqual(snakeHeadNext, food)) { //没吃到食物
  21.             Map[snakeBody.shift()] = 0; //先去除蛇尾
  22.             if (snakeBody.some(x=>pairEqual(x,snakeHeadNext)) || !snakeHeadNext.every(x => 0<=x == x < SpecialLen)) //蛇头不对
  23.                 return document.write("Game Over"); //overwrite all
  24.         }
  25.         snakeBody.push(snakeHeadNext);
  26.         Map[snakeHeadNext] = 1; //蛇头合适,加入蛇身
  27.         while (snakeBody.some(x => pairEqual(x, food)))
  28.             food = [Math.floor(Math.random() * SpecialLen), Math.floor(Math.random() * SpecialLen)];
  29.         Map[food] = 2;
  30.         for(let i =0;i<SpecialLen ;i++)
  31.             for(let j =0;j<SpecialLen ;j++){
  32.                 switch (Map[[i,j]]) {
  33.                     case 1:ctx.fillStyle= purple;break;
  34.                     case 2:ctx.fillStyle= green;break;
  35.                     default:ctx.fillStyle= grey;break;
  36.                 }
  37.                 ctx.fillRect(i*SpecialLen,j*SpecialLen, SpecialLen, SpecialLen)
  38.           }
  39.         setTimeout(arguments.callee, 100); //130ms后执行function 一次
  40.     }()
  41. </script>
  42. </body>
  43. </html>

40行版本去除注释

1500字符

  1. <!doctype html>
  2. <html>
  3. <body>
  4. <canvas id="1" width="400" height="400" ></canvas>
  5. <script>
  6.     let ctx = document.getElementById("1").getContext("2d");
  7.     let Len = 20, dir = 2, dirNow;
  8.     let food = [2, 0];
  9.     let Snake = [[0, 0], [1, 0]];
  10.     let Map = {0,0:1,1,0:1};
  11.     let dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]];
  12.     let pairEqual = ((p1, p2) => p1[0] == p2[0] && p1[1] == p2[1]);
  13.     document.onkeydown = function (env) {
  14.         arr = env.keyCode - 37;
  15.         if (0 <= arr == arr < 4 && dirNow !== (arr + 2) % 4)
  16.             dir = arr;
  17.     };
  18.     !function () {
  19.         let Head = Snake[Snake.length-1].map((x, i) => x + dirMat[dirNow=dir][i]);
  20.         if (!pairEqual(Head, food)) {
  21.             Map[Snake.shift()] = 0;
  22.             if (Snake.some(x=>pairEqual(x,Head)) || !Head.every(x => 0<=x == x < Len))
  23.                 return document.write("Game Over");
  24.         }
  25.         Snake.push(Head);
  26.         Map[Head] = 1;
  27.         while (Snake.some(x => pairEqual(x, food)))
  28.             food = [~~(Math.random() * Len), ~~(Math.random() * Len)];
  29.         Map[food] = 2;
  30.         for(let i =0;i<Len ;i++)
  31.             for(let j =0;j<Len ;j++){
  32.                 switch (Map[[i,j]]) {
  33.                     case 1:ctx.fillStyle= purple;break;
  34.                     case 2:ctx.fillStyle= green;break;
  35.                     default:ctx.fillStyle= grey;break;
  36.                 }
  37.                 ctx.fillRect(i*Len,j*Len, Len, Len)
  38.             }
  39.         setTimeout(arguments.callee, 100);
  40.     }()
  41. </script>
  42. </body>
  43. </html>

   

20行版本

  1. <!doctype html>
  2. <html>
  3. <body>
  4. <canvas id="can" width="400" height="400" style="background: Black"></canvas>
  5. <script>
  6.     var sn = [ 42, 41 ], dz = 43, fx = 1, n, ctx = document.getElementById("can").getContext("2d");
  7.     function draw(t, c) {
  8.         ctx.fillStyle = c;
  9.         ctx.fillRect(t % 20 * 20 + 1, ~~(t / 20) * 20 + 1, 18, 18);
  10.     }
  11.     document.onkeydown = function(e) {
  12.         fx = sn[1] - sn[0] == (n = [ -1, -20, 1, 20 ][(e || event).keyCode - 37] || fx) ? fx : n
  13.     };
  14.     !function() {
  15.         sn.unshift(n = sn[0] + fx);
  16.         if (sn.indexOf(n, 1) > 0 || n<0||n>399 || fx == 1 && n % 20 == 0 || fx == -1 && n % 20 == 19)
  17.             return alert("GAME OVER");
  18.         draw(n, "Lime");
  19.         if (n == dz) {
  20.             while (sn.indexOf(dz = ~~(Math.random() * 400)) >= 0);
  21.             draw(dz, "Yellow");
  22.         } else draw(sn.pop(), "Black");
  23.         setTimeout(arguments.callee, 130);
  24.     }();
  25. </script>
  26. </body>
  27. </html>

   

几个常见问题

  1. 蛇尾应该比蛇头先消失,蛇头应该比食物先生成,
  2. 蛇不能走 当前相反的方向,可以用长度为4的蛇进行测试

以上是关于40行贪吃蛇 原生js的主要内容,如果未能解决你的问题,请参考以下文章

使用前端原生 js,贪吃蛇小游戏

纯原生JS面向对象构造函数方法实现贪吃蛇小游戏

原生web实现贪吃蛇

javascript:用原生js模拟贪吃蛇游戏练习

13行js写贪吃蛇游戏

100行Python代码,轻松完成贪吃蛇小游戏?