使用canvas实现简单的贪吃蛇游戏,html+css+js
myzbx 2025-01-11 15:34 20 浏览
一.话不多,先瞅效果:
又在别的地方嫖到了这个效果研究了亿下下,制作过程如下(超详细):
二.实现过程(源码在最后):
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>
相关推荐
- 为什么钟表的指针是从左向右顺时针转?
-
所有的钟表指针都是从左向右转的,所以我们就用它来表示旋转方向了。那么,为什么钟表都是从左向右转呢?正着转也好,反着转也好,一圈不都是12小时吗?这就要从钟表的前身说起了。在钟表出现之前,人们使用过一种...
- 牛人将电子钟改造高精度时钟,日误差0.26秒!解决走时不准通病
-
家里有好多个电子钟,精度各种参差不齐,然后走时就是各种混乱,是可忍孰不可忍……自打发现8025这个好玩意儿之后,就决定不忍了。第一个上场的聪明钟,为啥叫聪明钟然后还走的不准。三节电池供电,其中3V给主...
- 篮球裁判手势图解之计时钟、得分替换和暂停手势
-
▋篮球裁判手势图解之计时钟手势停止计时钟手势,伸开手掌,垂直举过头部。犯规停止计时钟手势,一拳握紧,垂直举过头部。计时开始手势,用手做劈柴动作,将垂直举过头部的手放下。▋篮球裁判手势图解之得分手势1...
- 罗马数字的起源与用途
-
一、罗马数字的诞生与进化罗马数字起源于古罗马帝国,拥有一个漫长而复杂的历史,始于公元前8世纪至9世纪,与古罗马帝国在帕兰丁山(PalantineHill)周围建立的时间大致相同。不过,罗马数...
- 基于 Arduino Nano R3 的红外遥控数字时钟
-
由于在ArduinoNano上没有足够的引脚来编写代码,该项目只有有限的功能(即使没有设置时间的设施)。通过添加红外线遥控器,我可以灵活地整合所有需要的功能(如果需要,可能会更多),不需要额外的...
- 大班必备33首数字歌,轻松学数学
-
适合大班宝贝的33首数学歌,让孩子们在玩中学,通过好玩、好记的的儿歌来了解数学的知识点,轻松学数学!以上所有有关数学概念的知识点,其中包含了钟表、点数、分解组成、加减、单双数、倒数正数、凑十、方位...
- 11的寓意和象征
-
在数字的王国里,每个数字都有其独特的内涵和象征意义。今天,我们将一起探索数字11的奥秘和象征意义。这个奇特的数字,不仅在我们的日常生活中扮演着重要的角色,而且在神秘主义和宗教中也占有的一席之地。首先,...
- 基于TM1637的数字时钟
-
方案介绍这个项目是一个原型,我将在我正在进行的其他数字时钟项目中使用。这是我计划在我的下一个数字时钟项目中使用的时间和闹钟设置机制的原型。我希望能给你提供到帮助。如果你想到任何改进,请告诉我。我会更乐...
- 【金龟子讲睡前故事】数字不见啦
-
“快做数学题!”妈妈大声吼邦邦。“啊,好烦呀!”邦邦回到屋里,对着数学练习册大声嚷嚷。考拉熊博士在邦邦的屋外听到邦邦的声音,自言自语说:“好像又在发脾气,我得去看看他。”考拉熊博士推门进去,只见邦邦大...
- SE 最终幻想 35 周年,《FF7 重制版》破坏剑数字时钟 9 月发售
-
IT之家3月9日消息,SE今日正式开设了《最终幻想》35周年纪念网站,天野喜孝绘制官方LOGO公布!值得一提的是,索尼PlayStation游戏发布会即将于北京时间3月10...
- 谁说数字钟就是黑白状?他们让你改变看法
-
如果我们没有了钟表,你会用什么衡量时间?是利用太阳的变化还是凭猜测?之前设计癖也介绍一些有趣的钟表,像是Edelkrone设计的无表针的Oqloq钟表,也有淡化了表针概念的轨道钟表,今天再给大...
- 杭州元宵游玩大赏|“人体时钟”亮相文三数字生活街区,还有元宵巡游活动等你嗨
-
钱江晚报·小时新闻记者方力通讯员冯晨晨刘静滴答滴答,在这个时钟里面有一位虚拟的“小姐姐”。她的工作内容就是不断地把分针擦掉,然后再画上新的分针,她每画一次分针擦干净后,再画上一条新的分针,就刚...
- 来用PPT做一只数字时钟动画
-
“什么是可见性?“可见性”即指PPT动画元素中的一种。在我们之前的图文教程《动画基础扫盲课,必修!》中提到过一些常用的PPT动画元素。分别为可见性,X,Y坐标,旋转,高度和宽度。而其中所谓的“可见性”...
- 苹果手机桌面时钟怎么显示 苹果手机桌面时钟显示操作
-
苹果手机系统流畅,系统使用起来很舒适,是很多人的首选。苹果时钟可以在桌面上显示数字时钟,如果在编辑主屏幕时,不小心把时钟删掉了,要怎么恢复呢?或者想要设置时钟显示,操作是什么样的呢?苹果手机桌面时钟怎...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 选择器 (30)
- CSS 轮廓 (30)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 中级教程 (30)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)