
canvas贪吃蛇效果 html+css+js
发布日期:2021-05-07 18:24:12
浏览次数:12
分类:原创文章
本文共 13537 字,大约阅读时间需要 45 分钟。
一.话不多,先瞅效果:
视频演示~
又在别的地方嫖到了这个效果研究了亿下下,制作过程如下(超详细):
二.实现过程(源码在最后):
1.定义canvas标签:
<canvas id="canvas"></canvas>
2.基本css样式:
#canvas{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); box-shadow: 0 0 10px rgb(150, 150, 150); }
position: absolute; 绝对定位。
top: 50%;
left: 50%;
transform: translate(-50%,-50%); 居中。
box-shadow: 0 0 10px rgb(150, 150, 150); 阴影。
3.开始js部分,获取标签:
var canvas = document.querySelector("#canvas");var ctx = canvas.getContext('2d');
4.定义基本变量:
//画布宽 var wide=600; //画布高 var high=600; // 变量,判断一次渲染中只识别按键一次 var kd = 0; //当前分数 var fraction =0; //速度,就是执行定时器的时间参数 var speed = 250; // 蛇的初始颜色 红色 var yanse = `red`; // 蛇数组,组成蛇的每一个方块 var snake = []; // 食物数组 var food = { }; // 蛇的移动方向,x轴:1为向右,-1为向左;y轴:1为向下,-1为向上 。不能斜着走,所以0为某轴无方向。 var diretion = { x:-1, y:0 } // 给画布宽高赋值 打算画一个长宽都是30个20px的方块画布 canvas.width = wide; canvas.height = high;
5. 初始化:
function chushi(){ //蛇初始长度为3个方块,位置如下(这个随意) for(let i =0;i<3;i++){ snake.push({ x: i+10, y: 10 }) } // 给食物一个随机位置和随机颜色 food = { x: parseInt(Math.random()*30), y: parseInt(Math.random()*30), color:`rgb(${ Math.random()*255},${ Math.random()*255},${ Math.random()*255})` } }
6. 绘制图形:
// 绘制图形 function draw(){ // 绘制显示当前分数的文字 ctx.fillStyle = 'rgba(255,255,255,0.5)'; ctx.font="50px 仿宋"; ctx.textAlign = 'center'; ctx.fillText("你的分数为:"+fraction+" 分",300,300); // 绘制方格,长宽都是30个,都是19px*19px的方格 for(let i=0;i<30;i++){ for(let j=0;j<30;j++){ ctx.fillStyle = 'rgba(255, 255, 255,.3)'; ctx.fillRect(i*20,j*20,19,19); } } // 绘制蛇 for(let i=0;i<snake.length;i++){ temp = snake[i]; ctx.fillStyle = yanse; ctx.fillRect(temp.x*20,temp.y*20,19,19); // 判断蛇头(第一个方块)是否与身体某个方块重合 ,就是头撞到身体 if(temp.x==snake[0].x&&temp.y==snake[0].y&&i!=0){ // 游戏结束,重新给初始化 alert('游戏结束~点击确认再来一次~'); fraction = 0; snake.length=0; chushi(); } } // 绘制食物,绘制一个圆形 ctx.beginPath(); ctx.fillStyle = food.color; ctx.arc(food.x*20+9.5,food.y*20+9.5,7,0,Math.PI*2,false); ctx.stroke(); ctx.fill(); ctx.closePath(); // 给蛇头绘制一个字符,☆ ,好区分头尾 ,也可省略 ctx.fillStyle = 'yellow'; ctx.font="15px 仿宋"; ctx.textAlign = "start"; ctx.fillText("☆",snake[0].x*20+2,snake[0].y*20+14.5); }
7.更新位置:
//更新 function update(){ // 建一个对象head,这个为蛇的新头,通过绘制新头,去掉尾部实现移动效果 var head = { }; //判断蛇头是否遇到边界,到边界则在另一边重新绘制 x轴 switch (snake[0].x+diretion.x){ case -1: head.x=29;break; case 30: head.x=0;break; // 没到边界则为当前位置加方向 default: head.x = snake[0].x+diretion.x; } //判断蛇头是否遇到边界,到边界则在另一边重新绘制 y轴 switch (snake[0].y+diretion.y){ case -1: head.y=29;break; case 30: head.y=0;break; // 没到边界则为当前位置加方向 default: head.y = snake[0].y+diretion.y; } // 判断新蛇头是否与食物重合,就是吃到食物 if(head.x==food.x&&head.y==food.y){ //蛇的颜色为吃到食物的颜色 yanse = food.color; // 重新给食物初始化 food = { x: parseInt(Math.random()*30), y: parseInt(Math.random()*30), color:`rgb(${ Math.random()*255},${ Math.random()*255},${ Math.random()*255})` } //在蛇尾添加一节 let temp = snake[length-1]; snake.push(temp); fraction+=1; // 吃完食物速度加快 if(speed>80){ //定时器间隔减10 speed = speed-10; // 清除原来定时器,重新绘制 clearInterval(time); time = setInterval(function () { kd = 0; ctx.clearRect(0, 0, wide, high); update(); draw(); }, speed); } } //添加新头 snake.splice(0,0,head); //去掉尾部 snake.pop(); }
8.判断点击键盘事件:
//判断点击事件 document.addEventListener('keydown', event=>{ switch (event.keyCode){ // 按了向上键 case 38: // 判断当前不是向下移动与还没按过键,否则蛇会重叠 if(diretion.y!=1&&kd==0){ // 重新给移动方向赋值 diretion.x=0; diretion.y=-1; kd=1; } break; // 下面以此类推一样的原理 case 39: if(diretion.x!=-1&&kd==0){ diretion.x=1; diretion.y=0; kd=1; } break; case 40: if(diretion.y!=-1&&kd==0){ diretion.x=0; diretion.y=1; kd=1; } break; case 37: if(diretion.x!=1&&kd==0){ diretion.x=-1; diretion.y=0; kd=1; } break; } })
9.设置定时器,开始动画:
chushi(); var time = setInterval(function(){ kd=0; ctx.clearRect(0,0,wide,high); update(); draw(); },speed);
三.完整代码:
<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; box-sizing: border-box; } body{ height: 100vh; } video{ position: fixed; z-index: -10; width: 100%; height: 100%; object-fit: cover; } #canvas{ position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); box-shadow: 0 0 10px rgb(150, 150, 150); } </style></head><body> <video src="video/rain.mp4" muted autoplay loop></video> <canvas id="canvas"></canvas> <script> var canvas = document.querySelector("#canvas"); var ctx = canvas.getContext('2d'); //画布宽 var wide=600; //画布高 var high=600; // 变量,判断一次渲染中只识别按键一次 var kd = 0; //当前分数 var fraction =0; //速度,就是执行定时器的时间参数 var speed = 250; // 蛇的初始颜色 红色 var yanse = `red`; // 蛇数组,组成蛇的每一个方块 var snake = []; // 食物数组 var food = { }; // 蛇的移动方向,x轴:1为向右,-1为向左;y轴:1为向下,-1为向上 。不能斜着走,所以0为某轴无方向。 var diretion = { x:-1, y:0 } // 给画布宽高赋值 打算画一个长宽都是30个20px的方块画布 canvas.width = wide; canvas.height = high; function chushi(){ //蛇初始长度为3个方块,每个位置如下(这个随意) for(let i =0;i<3;i++){ snake.push({ x: i+10, y: 10 }) } // 给食物一个随机位置和随机颜色 food = { x: parseInt(Math.random()*30), y: parseInt(Math.random()*30), color:`rgb(${ Math.random()*255},${ Math.random()*255},${ Math.random()*255})` } } // 绘制图形 function draw(){ // 绘制显示当前分数的文字 ctx.fillStyle = 'rgba(255,255,255,0.5)'; ctx.font="50px 仿宋"; ctx.textAlign = 'center'; ctx.fillText("你的分数为:"+fraction+" 分",300,300); // 绘制方格,长宽都是30个,都是19px*19px的方格 for(let i=0;i<30;i++){ for(let j=0;j<30;j++){ ctx.fillStyle = 'rgba(255, 255, 255,.3)'; ctx.fillRect(i*20,j*20,19,19); } } // 绘制蛇 for(let i=0;i<snake.length;i++){ temp = snake[i]; ctx.fillStyle = yanse; ctx.fillRect(temp.x*20,temp.y*20,19,19); // 判断蛇头(第一个方块)是否与身体某个方块重合 ,就是头撞到身体 if(temp.x==snake[0].x&&temp.y==snake[0].y&&i!=0){ // 游戏结束,重新给初始化 alert('游戏结束~点击确认再来一次~'); fraction = 0; snake.length=0; chushi(); } } // 绘制食物,绘制一个圆形 ctx.beginPath(); ctx.fillStyle = food.color; ctx.arc(food.x*20+9.5,food.y*20+9.5,7,0,Math.PI*2,false); ctx.stroke(); ctx.fill(); ctx.closePath(); /* var img = new Image(); img.src = "img/snake/orange.png"; img.onload = function(){ ctx.drawImage(img,food.x*20,food.y*20,19,19); } */ // 给蛇头绘制一个字符,☆ ,好区分头尾 ,也可省略 ctx.fillStyle = 'yellow'; ctx.font="15px 仿宋"; ctx.textAlign = "start"; ctx.fillText("☆",snake[0].x*20+2,snake[0].y*20+14.5); } //更新 function update(){ // 建一个对象head,这个为蛇的新头,通过绘制新头,去掉尾部实现移动效果 var head = { }; //判断蛇头是否遇到边界,到边界则在另一边重新绘制 x轴 switch (snake[0].x+diretion.x){ case -1: head.x=29;break; case 30: head.x=0;break; // 没到边界则为当前位置加方向 default: head.x = snake[0].x+diretion.x; } //判断蛇头是否遇到边界,到边界则在另一边重新绘制 y轴 switch (snake[0].y+diretion.y){ case -1: head.y=29;break; case 30: head.y=0;break; // 没到边界则为当前位置加方向 default: head.y = snake[0].y+diretion.y; } // 判断新蛇头是否与食物重合,就是吃到食物 if(head.x==food.x&&head.y==food.y){ //蛇的颜色为吃到食物的颜色 yanse = food.color; // 重新给食物初始化 food = { x: parseInt(Math.random()*30), y: parseInt(Math.random()*30), color:`rgb(${ Math.random()*255},${ Math.random()*255},${ Math.random()*255})` } //在蛇尾添加一节 let temp = snake[length-1]; snake.push(temp); fraction+=1; // 吃完食物速度加快 if(speed>80){ //定时器间隔减10 speed = speed-10; // 清除原来定时器,重新绘制 clearInterval(time); time = setInterval(function () { kd = 0; ctx.clearRect(0, 0, wide, high); update(); draw(); }, speed); } } //添加新头 snake.splice(0,0,head); //去掉尾部 snake.pop(); } //判断点击事件 document.addEventListener('keydown', event=>{ switch (event.keyCode){ // 按了向上键 case 38: // 判断当前不是向下移动与还没按过键,否则蛇会重叠 if(diretion.y!=1&&kd==0){ // 重新给移动方向赋值 diretion.x=0; diretion.y=-1; kd=1; } break; // 下面以此类推一样的原理 case 39: if(diretion.x!=-1&&kd==0){ diretion.x=1; diretion.y=0; kd=1; } break; case 40: if(diretion.y!=-1&&kd==0){ diretion.x=0; diretion.y=1; kd=1; } break; case 37: if(diretion.x!=1&&kd==0){ diretion.x=-1; diretion.y=0; kd=1; } break; } }) chushi(); var time = setInterval(function(){ kd=0; ctx.clearRect(0,0,wide,high); update(); draw(); },speed); </script></body></html>
四.总结:
最近又在听蕊希电台了。干点鸡汤~
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年04月11日 12时49分21秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Edit编辑框自动换行与长度
2019-03-04
英语02_单词词性
2019-03-04
低通滤波器的设计
2019-03-04
窄带随机过程的产生
2019-03-04
随机四则运算
2019-03-04
Java面向对象
2019-03-04
JAVA带标签的break和continue
2019-03-04
Java获取线程基本信息的方法
2019-03-04
Java集合Collection
2019-03-04
SpringBoot快速入门
2019-03-04
医疗管理系统-手机快速登录和SpringSecurity权限控制
2019-03-04
网页实现微信登录
2019-03-04
vue源码分析(MVVM篇)
2019-03-04
React(八)- ReactUI组件库及Redux的使用
2019-03-04
TypeScript系列(一)- TypeScript简介与编译配置
2019-03-04
TypeScript系列文章导航
2019-03-04
hibernate和mybatis的区别
2019-03-04
Java中Map的用法详解
2019-03-04
base64编码字符串和图片的互转
2019-03-04
汉字转为拼音
2019-03-04