20行code实现贪吃蛇功能
来源:互联网 发布:域名中国 编辑:程序博客网 时间:2024/05/16 11:10
看到一位大神用20行代码就写出了一个贪吃蛇的小游戏,感觉被惊艳到了,就试着读了一下这段代码,阅读过程中不断为作者写法的巧妙而叫绝,其中我发现自己对运算符优先级和一些js的技巧不是很清楚,所以看完之后决定把思路分享出来,方便和我一样的小白学习。
我对代码稍稍做了些修改,并添加了一些注释,方便理解。
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>贪吃蛇重构</title> <style> body { display: flex; height: 100vh; margin: 0; padding: 0; justify-content: center; align-items: center; }
</style>
</head>
<body>
<canvas id="can" width="400" height="400" style="background-color: black">对不起,您的浏览器不支持canvas</canvas>
<script> var snake = [41, 40],
//snake队列表示蛇身,初始节点存在但不显示 direction = 1,
//1表示向右,-1表示向左,20表示向下,-20表示向上 food = 43,
//食物的位置 n,
//与下次移动的位置有关 box = document.getElementById('can').getContext('2d');
//从0到399表示box里[0~19]*[0~19]的所有节点,每20px一个节点 function draw(seat, color) { box.fillStyle = color; box.fillRect(seat % 20 *20 + 1, ~~(seat / 20) * 20 + 1, 18, 18);
//用color填充一个矩形,以前两个参数为x,y坐标,后两个参数为宽和高。 } document.onkeydown = function(evt) { //当键盘上下左右键摁下的时候改变direction direction = snake[1] - snake[0] == (n = [-1, -20, 1, 20][(evt || event).keyCode - 37] || direction) ? direction : n; }; !function() { snake.unshift(n = snake[0] + direction); //此时的n为下次蛇头出现的位置,n进入队列 if(snake.indexOf(n, 1) > 0 || n < 0 || n > 399 || direction == 1 && n % 20 == 0 || direction == -1 && n % 20 == 19) { //if语句判断贪吃蛇是否撞到自己或者墙壁,碰到时返回,结束程序 return alert("GAME OVER!"); } draw(n, "lime");
//画出蛇头下次出现的位置 if(n == food) {
//如果吃到食物时,产生一个蛇身以外的随机的点,不会去掉蛇尾 while (snake.indexOf(food = ~~(Math.random() * 400)) > 0); draw(food, "yellow"); } else {
//没有吃到食物时正常移动,蛇尾出队列 draw(snake.pop(),"black"); } setTimeout(arguments.callee, 150); //每隔0.15秒执行函数一次,可以调节蛇的速度 }();
</script>
</body>
</html>
首先,我们要知道做一个贪吃蛇最主要的是什么,是做出蛇活动的场所和如何使蛇动起来。
我们先看蛇活动的场所:
<!-- html -->
<canvas id="can" width="400" height="400" style="background-color: black"> 对不起,您的浏览器不支持canvas
</canvas>
<!-- js -->
box = document.getElementById('can').getContext('2d');
这是一个400px*400px
的canvas
,思路是以20px*20px
为一个方格,组成20
行20
列的方阵,总共400
格,然后绿色填充的格子表示蛇身,用黄色表示食物。这400
个格子和数字0~399
一一对应,对应的方式就是以20
作为基数,n / 20
再取整表示第几行,n % 20
表示第几列。行数和列数都用0~19
表示。
蛇用一个一维数组表示,每个值都是这400
个数中的一个,用var snake = [41, 40];
初始化这条蛇,索引0
为蛇头。food
表示食物的位置,direction
表示蛇头下一次运动的转向。蛇的运动就用添加和删除数组元素来实现,每次执行绘制蛇头,去掉蛇尾,循环执行使蛇运动。
下边从函数运行的起始处开始看:
!function() {}();
什么鬼?这其实是立即执行函数IIFE
的另一种写法。继续往下看,给蛇头添加一个节点n
,其值为当前蛇头的值加direction
的值,如此一来就能理解为什么要用20
表示向下,-20
表示向上了。
再下一行是一个if
语句,其中值得提醒的是&&
的优先级高于||
,这个语句就是判断即将出现的蛇头是不是属于蛇身,或者跑到box外边去了。如果没有死亡,就把这个蛇头绘制出来,下边就看看绘制的代码:
function draw(seat, color) {
box.fillStyle = color;
box.fillRect(seat % 20 *20 + 1, ~~(seat / 20) * 20 + 1, 18, 18);
}
填充时填充18*18
的像素,留1px
边框。.fillRect()
中第一个参数就是要绘制的矩形的x
坐标seat % 20 *20 + 1
,即先得到所要绘制的矩形块在方阵中的位置:第~~(seat / 20)
行,第seat % 20
列,再* 20 + 1
具体到像素点。
可能这个~~
有点难理解,我感觉在这里的用处应该和Math.floor()
差不多,对一个浮点型的数取反再取反,得到的数就是去掉小数位的整数了。
回到前面
,又是一个判断语句,判断下次蛇头出现的位置是不是和当前的食物的位置相同,如果相同,生成下一个食物,食物的位置为一个随机数,但是要判断这个点不是出现在当前的蛇身上,绘制食物。
如果没有吃到食物,即蛇在正常运动时,每向前一次,将蛇尾弹出,并利用其返回值将这个点重新绘制为黑色。
最后的setTimeout
,循环执行当前函数,设置执行周期来调蛇的移动速度。
到了这里,我们发现这条蛇已经可以动了,加上键盘的操作就完成了:
document.onkeydown = function(evt) {
direction = snake[1] - snake[0] == (n = [-1, -20, 1, 20][(evt || event).keyCode - 37] || direction) ? direction : n;};
将这个函数绑定到键盘事件上,evt || event
用法的原因这里有详细的解释,是为了兼容ie
。
三目运算符?
前边的判断语句又可分为两部分:
snake[1] - snake[0]
的值应该就是-direction
,按理说此处写成-direction
应该和原来是一个效果,那为什么没有这么做呢,因为如果这样写,玩家可能在一个函数周期中多次改变direction
的值,最后使得direction
和当前真正的运动方向不一致,导致游戏崩溃。在
==
后边,[-1, -20, 1, 20][(evt || event).keyCode - 37]
中前边的[]
是一个数组,后边的[]
是取索引,左上右下四个键的keyCode
分别为37, 38, 39, 40
,计算后的索引为0, 1, 2, 3
,使方向键与direction
的取值对应起来。这里的巧妙之处在于如果按下的按键不是方向键,在数组中将得不到对应的值,返回undefine
。此时,由于之后的||
运算符,n
会取到direction
原来的值。
再用三目运算符来判断,如果按键方向不是反方向,就更新direction
的值。
以上虽然都是一些基础的东西,但是感觉还是挺好玩的。要是哪里理解的不对还希望指证出来,共同进步。
- 20行code实现贪吃蛇功能
- 实现贪吃蛇部分功能
- jquery实现贪吃蛇功能
- C++贪吃蛇200行以内实现完整功能
- 20行JS代码实现贪吃蛇
- 使用js实现贪吃蛇的部分功能
- 功能异常简单的贪吃蛇(队列实现)
- 【05】20行js代码实现的贪吃蛇小游戏
- 小白理解 js 20行代码实现贪吃蛇
- 30行C代码实现贪吃蛇
- 63行代码实现贪吃蛇
- javascript(23行) 实现贪吃蛇
- 贪吃蛇C实现
- js实现贪吃蛇
- JavaScript实现贪吃蛇
- javascript实现贪吃蛇
- javascript实现贪吃蛇
- QT实现贪吃蛇
- spring 版本不同导致json解析问题,解决方案
- 创建和销毁对象
- <Python Learning>进阶
- static关键字
- C++矩阵处理库--Eigen初步使用
- 20行code实现贪吃蛇功能
- 基于微博用户标签的中医药情绪分析
- java重载类型自动转换学习
- 华为-最高分是多少-Java
- tensorflow1.1/构建神经网络分类
- 极路由HC5661a刷潘多拉固件后配置python环境运行脚本登陆dr.com校园网
- Android自定义动画三-SVG动画
- 一个继承自RelativeLayout的输入法监听布局
- 持续集成开发环境搭建