尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用 JavaScript 事件从零搭出可玩贪吃蛇:完整指南

用 JavaScript 事件从零搭出可玩贪吃蛇:完整指南 用 JavaScript 事件从零搭出可玩贪吃蛇完整指南【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum不引入任何框架用一个JavaScript 贪吃蛇把事件驱动讲透键盘事件是扳机setTimeout游戏循环是心跳DOM 渲染负责把二维网格搬上屏幕。四个小问题一次跑通。动手前先记住三个角色键盘 扳机每按一次方向键就触发一条变向指令蛇本身不会主动转弯。setTimeout 心跳按固定节奏推进回合节奏想快想慢随时能改。二维网格 舞台蛇、食物、边界都只是这块棋盘上的坐标。问题一先把画面画出来网格用二维数组建模原因很简单格子的位置可以直接用行、列两个下标定位蛇每走一步只是把新坐标处写入的字符改掉而已不需要任何图形库。先准备一个容器和格子样式注意box-sizing这一行别省否则边框会毁掉布局后文有坑可查div idboard/div style .cell { width: 20px; height: 20px; border: 1px solid #999; } .cell { box-sizing: border-box; } /* 边框不许撑大格子 */ .cell { display: inline-block; } .snake { background: green; } .food { background: red; } /style script srcsnake.js/script再构建棋盘和初始状态每个格子只存一个字符空格代表空位O是蛇F是食物const N 40; let grid []; for (let r 0; r N; r) grid.push(Array(N).fill( )); let snake { dir: r, body: [[20, 20]] }; // 第一个元素是蛇头 let food { at: [5, 5] }; grid[20][20] O; grid[5][5] F; let score 0, tick 200, over false;draw()的职责就是把这块数组变成屏幕上一组divfunction draw() { const board document.getElementById(board); board.innerHTML ; // 先清屏否则格子会越叠越多 grid.forEach((row, r) row.forEach((v, c) { const cell document.createElement(div); cell.className cell (v O ? snake : v F ? food : ); board.appendChild(cell); })); }调用一次draw()此时页面应该出现一块 40×40 的格子正中有个绿色蛇头旁边一点处是红色食物。问题二按方向键蛇怎么变向先说现象按下任意方向键控制台立刻打印出一个新方向。背后的原理一句话就能说清回调是一个被抛向未来的函数。传给addEventListener的函数此刻并没有执行它被浏览器收好等按键真正发生的那一刻才由浏览器替你调用并按键信息打包在事件对象里递进来document.addEventListener(keydown, (e) { const keys { ArrowUp: u, ArrowDown: d, ArrowLeft: l, ArrowRight: r }; if (keys[e.key]) { snake.dir keys[e.key]; console.log(当前方向:, snake.dir); } });此时你应该看到控制台的输出随按键实时变化。蛇还不会动但控制通道已经打通了。问题三不按键蛇为什么还自己走 先分清两个定时器setInterval按固定节拍触发中途想变速很别扭而setTimeout是在本回合结束后才调度下一回合每一轮都重新读取最新的tick值改速立刻生效——游戏循环就该用它来驱动。循环的骨架只有几步移动、重绘、判胜负没死才预约下一回合function loop() { move(); draw(); const head snake.body[0]; if (hitWall(head) || hitSelf(head)) { over true; alert(Game Over! 得分: score); return; // 不再预约下一回合循环自然终止 } setTimeout(loop, tick); } loop();此时你应该看到蛇每隔 200 毫秒自动向右滑一格全程不需要碰键盘。问题四什么情况算输一共四条规则各说一遍吃食物变长新蛇头坐标等于食物坐标时这一回合不弹尾巴蛇自然长一节随后食物换个随机位置重生placeFood()就是随机挑行列、在网格写个F。撞墙蛇头坐标走出 0 到 39 的范围本局结束。撞自己新蛇头与蛇身里任意一节重叠本局结束——蛇尾除外它这一回合马上就挪走了。计分蛇越长吃一个食物的得分越高鼓励把蛇养长。move()用头插尾删实现移动每回合把新蛇头插进数组前部再弹掉尾部一节长度就保持不变吃到食物时跳过弹尾长度就 1function move() { const head snake.body[0]; const next [head[0], head[1]]; // 复制别共享引用 if (snake.dir u) next[0]--; if (snake.dir d) next[0]; if (snake.dir l) next[1]--; if (snake.dir r) next[1]; if (isFood(next)) { score snake.body.length; // 蛇越长分越高 placeFood(); // 食物换到新的随机位置 } else { snake.body.pop(); // 先弹尾 } snake.body.unshift(next); // 再插新头 }两个判负函数每样只有一行比较function isFood(pos) { return pos[0] food.at[0] pos[1] food.at[1]; } function hitWall(pos) { return pos[0] 0 || pos[1] 0 || pos[0] N || pos[1] N; } function hitSelf(pos) { return snake.body.slice(0, -1).some( // 蛇尾不算 (seg) seg[0] pos[0] seg[1] pos[1]); }补上这些之后整局应该完全可玩撞墙结束、咬到自己结束、吃食物变长并加分。最容易踩的四个坑边框撑大格子导致换行错位每个格子的 1px 边框是加在 20px 宽度之外的一整行的实际宽度超出容器排几排就断行。解法box-sizing: border-box前面样式里已经写了。复制蛇头坐标时忘了拷贝直接写const next head会让next和蛇头指向同一个数组改next的同时污染整条蛇身。解法用[head[0], head[1]]手动复制出新数组。渲染前没清屏每画一次就再塞进 1600 个 div十几回合后页面开始卡顿。解法draw()开头先board.innerHTML 。允许 180° 反向自撞蛇向右走时你按左蛇头直接咬上第二节身体瞬间判负。解法按下的方向若与当前方向正好相反就忽略这次输入。跑通之后可以玩点什么逐步加速每吃一个食物就把tick调小一点设个 50 毫秒的下限setTimeout调度时读到的就是新值立刻生效。图片蛇身把纯色方块换成一组img元素用几张网络图片拼出有花纹的蛇身。加权计分给在棋盘中心吃到食物加额外分或者让得分随蛇长按平方增长做出一张值得冲的高分榜。收尾把四个问题跑通你已经完整过了一遍事件驱动编程的循环监听器接住输入回调承接逻辑定时器维持节奏DOM 负责输出。卡壳的时候翻翻 事件与效果课件 里的冒泡与委托原理或去 事件驱动课件 温习一下回调为什么重要。最后把这条蛇推到自己的仓库里给朋友看看——这是验证这个前端入门实战项目真正属于你的最好方式。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表