先上源码, 版本是 ES6
13 行常规 (700bytes) | https://gist.github.com/Haozun/af948545560805eb7771231eb7f446c0 |
压缩后的 500bytes(当然两处 document 还是可以用 eval 压缩的) | https://gist.github.com/Haozun/af948545560805eb7771231eb7f446c0 |
之前很火的 20 行代码地址 (有 BUG)(900bytes) |
一维数组 700char
(0,0) 位置的蛇身用 0 表示,(0,1) 用 1,(1,0) 用 10 表示, 以此类推
因为就 13 行 js,
第 4 行 是声明
第 5 行 比较难理解, 可以把?: 运算符, 拆分为 4 行 if 语句; 可以参考下面的 二维数组 的版本
第 9 行 0|x 和 ~~x 和 x>>0 都能去除 x(number) 的尾数
- <!DOCTYPE html>
- <canvas id="1" width="400" height="400"></canvas>
- <script>
- let dir=1,food=3,snk=[1,0],ctx=document.getElementById("1").getContext("2d")
- document.onkeydown=e
- =>{ dir =snk[0]-snk[1]==-(tmp = [-1,-10,1,10][e.keyCode-37]||dir)?dir:tmp }
- setInterval(()=>{
- snk.unshift(Head = snk[0] + dir)
- if(Head!=food) snk.pop()
- else while(snk.includes(food=0|Math.random()*10*10)) ;
- if(snk.indexOf(Head,1)!=-1||(dir==1&&Head%10==0)||(dir==-1&&Head%10==9)||Head<0||Head>=100)
- return document.write(0&snk.shift()) // 死亡记录蛇长
- for(let i=0; i<100; i++){
- ctx.fillStyle = '#0'+(food==i)*9910+snk.includes(i)*1990
- ctx.fillRect(i%10*40,(i-i%10)*4, 40,40)
- }
- },100)
- </script>
点击运行 https://haozun.github.io/snakeGame/snakeGame.html
颜色效果
- <!DOCTYPE html>
- <canvas id="1" width="400" height="400"></canvas>
- <script>
- let dir=1,food=3,snk=[1,0],n_=0, ctx=document.getElementById("1").getContext("2d")
- document.onkeydown=e
- =>{ dir =snk[0]-snk[1]==-(tmp = [-1,-10,1,10][e.keyCode-37]||dir)?dir:tmp }
- setInterval(()=>{
- snk.unshift(Head = snk[0] + dir)
- if(Head!=food) snk.pop()
- else while(snk.includes(food=0|Math.random()*10*10)) ;
- if(snk.indexOf(Head,1)!=-1||(dir==1&&Head%10==0)||(dir==-1&&Head%10==9)||Head<0||Head>=100)
- return alert("died"+ ++n_+"times") // 死亡记录死亡次数
- for(let i=0 ; i<100; i++){
- ctx.fillStyle = '#0'+~~((food===i)*13000*Math.random())+~~(snk.includes(i)*3000*Math.random())
- ctx.fillRect(i%10*40,(i-i%10)*4, 40,40)
- }
- },120)
- </script>
点击运行 https://haozun.github.io/snakeGame/colorSnake.html
说明
如果自己要写的话: 要注意两点
蛇尾应该比蛇头先消失, 蛇头应该比食物先生成,
蛇不能走当前相反的方向
可以用长度为 4 的蛇进行测试
代码风格
省去没必要的标签
https://google.github.io/styleguide/htmlCSSguide.html#Optional_Tags https://google.github.io/styleguide/htmlcssguide.html
if() return 只用一行
https://google.github.io/styleguide/cppguide.html
除了键盘响应那里用 3 目运算符能省 3 行之外, 其他地方都没必要用
二维数组
以上的都是用一维数组实现的, 下面的用二维数组写; 要简化也能简化到 17 行以内 900char 以内 (比 20 行的那个短就是了), 不过没有必要
带注释的 1100char
- <!DOCTYPE html>
- <canvas id="1" width="400" height="400" style="border: 1px solid"></canvas>
- <script>
- ctx = document.getElementById("1").getContext("2d") //CanvasRenderingContext2D inferface
- let Len = 10, dir = 2, dirNow ; //dirNow 后面解释
- food = [3, 0]; Snake = [[0, 0], [1, 0]] // 食物的坐标, 蛇身的坐标用 Snake 数组记录
- Map = {'0,0':'#52a', '1,0':'#52a'} // 用来记录绘图颜色的 <span style="color: #5c6370;" ztid="966" ow="30" oh="16"> 地图
- dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]] // 方向矩阵
- pairEq = ((p1
- , p2
- ) => p1[0] == p2[0] && p1[1] == p2[1]) // 检测 <span style="color: #5c6370;" ztid="1033" ow="141" oh="16"> 两数对 是否相等的函数
- document.onkeydown = e
- =>{
- if (37 <= e.keyCode == e.keyCode <41 && dirNow != ( (e.keyCode - 35) % 4) ) // 确定是 <span style="color: #5c6370;" ztid="1079" ow="252" oh="17"> 方向键 并且 保证方向与当前运动方向相反
- dir = e.keyCode -37
- }
- !function () {
- Head = Snake[Snake.length-1].map((x
- , i
- ) => x + dirMat[dirNow=dir][i]); // 得到头部接下来的移动位置
- if (!pairEq(Head, food))
- Map[Snake.shift()]='#fff' // 必须先删尾巴, 才能加入头部, 吃没吃到食物是唯一判断标准
- if (Snake.some(x
- =>pairEq(x,Head)) || !Head.every(x
- => 0<=x == x <Len)) // 判断蛇头是否撞到蛇身或墙壁
- return document.write("Game Over") // 这样调用 document.write 会把页面全部清空
- Snake.push(Head); // 可以加入头部
- while (Snake.some(x
- => pairEq(x, food))) // 加入新头后, 生成食物更方便
- food = [~~(Math.random() * Len), ~~(Math.random() * Len)]; // 因为 js 没有整形的概念, ~~ 现在相当于向原点舍去
- Map[Head] = '#52a' ; Map[food] = '#ad5'
- for( k in Map){
- ctx.fillStyle= Map[k]
- ctx.fillRect(parseInt(k[0])*40,parseInt(k[2])*40,40,40) //e.g. k="1,3",
- // 也因此地图大小限制为
- 10
- }
- setTimeout(arguments.callee, 100); //100ms
- // 后调用此函数一次
- }()
- </script>
七彩的 (主要是比较好看)1100char
- <!DOCTYPE html>
- <canvas id="1" width="400" height="400" style="border: 1px solid"></canvas>
- <script>
- ctx = document.getElementById("1").getContext("2d")
- let Len = 10, dir = 2, dirNow ;
- food = [3, 0]; Snake = [[0, 0], [1, 0]]
- Map = {'0,0':'fff', '1,0':'fff'}
- dirMat = [[-1, 0], [0, -1], [1, 0], [0, 1]]
- pairEq = ((p1
- , p2
- ) => p1[0] == p2[0] && p1[1] == p2[1])
- document.onkeydown = e
- =>{
- if (37 <= e.keyCode == e.keyCode <41 && dirNow != ( (e.keyCode - 35) % 4) )
- dir = e.keyCode -37
- }
- !function () {
- Head = Snake[Snake.length-1].map((x
- , i
- ) => x + dirMat[dirNow=dir][i]);
- if (!pairEq(Head, food)) Map[Snake.shift()]='0'
- if (Snake.some(x
- =>pairEq(x,Head)) || !Head.every(x
- => 0<=x == x <Len))
- return document.write("Game Over")
- Snake.push(Head);
- while (Snake.some(x
- => pairEq(x, food)))
- food = [~~(Math.random() * Len), ~~(Math.random() * Len)];
- Map[Head] = Map[food] = 'fff'
- for( k in Map){
- ctx.fillStyle='#'+(0xfff-~~(parseInt(Map[k],16)*Math.random())).toString(16)
- ctx.fillRect(parseInt(k[0])*40,parseInt(k[2])*40,46,43)
- }
- setTimeout(arguments.callee, 100);
- }()
- </script>
来源: https://www.cnblogs.com/migeater/p/9306843.html