HTML 5 + CSS 3 + JavaSript 实现贪吃蛇
参考代码:经典贪吃蛇源码(含注释)
源代码
<!DOCTYPE html>
<html>
<head>
<title>Retro Snake</title>
<link rel="icon" href="https://raw.githubusercontent.com/CourserLi/JavaScirpt-snake/master/head.ico" type="image/x-icon"/>
<style type="text/css">
body {background-image:url(https://raw.githubusercontent.com/CourserLi/JavaScirpt-snake/master/pic.jpg);background-size:100%;}
body {background-repeat:no-repeat;}
body {margin:100px;text-align:center;}
h1 {font-size:210%;}
h1 {font-family:Georgia,Serif;}
</style>
</head>
<body>
<!--设置id,宽400像素,高400像素,背景颜色设置为灰色-->
<canvas id="canv" width="400" height="400" style="background-color:gray"></canvas>
</canvas>
<h1>Courser Li</h1>
<script>
//声明变量
//设置canvas画布的绘图的环境,当前唯一支持的参数是2d
var box=document.getElementById('canv').getContext('2d'); //用于绘制矩形的变量
//声明一个变量表示蛇
var snake;
//声明键盘事件的变量,1表示向右,-1向左,20向下,-20向上
var direction;
//声明蛇头
var n;
//声明食物变量
var food;
//声明速度初始变量
speed=100;
//绘制地图
function draw(point,color)
{
//fillStyle()方法为设置用于填充绘画的颜色
box.fillStyle=color;
//fillRect()方法用于绘制“被填充”的矩形
box.fillRect(point%20*20+1,~~(point/20)*20+1,18,18); //行 列 长 宽(长宽不能大于20,因为要在矩形直接留间隙)
}
//各种变量初始化,背景初始化
function ready()
{
//循环绘制地图块
for(var i=0;i<400;i++)
draw(i,"#313131");
//对蛇和食物进行静态赋值并绘制到地图上
snake=[66,65,64];
direction=1; //起始方向向右
food=344;
draw(food,"yellow");
draw(66,"#00b7ee");
draw(65,"#00b7ee");
draw(64,"#00b7ee");
}
//自动运行函数
(function(){ready();}());
//核心算法
function run()
{
//在游戏开始以后“开始游戏”按钮变为不可点击状态
document.getElementById("butn").setAttribute("disabled",true);
//用unshift()方法向数组的开头添加一个新元素,新元素为蛇下一步所移动的坐标
snake.unshift(n=snake[0]+direction);
//边界判断,如果蛇头碰到上下左右四个边或者碰到自己的身子
//游戏结束,初始化游戏,将“开始游戏”按钮设置为可以点击,点击开始按钮可以重新进行游戏
if(snake.indexOf(n,1)>0||n<0||n>399||(direction==-1&&n%20==19)||(direction==1&&n%20==0))
{
ready();
document.getElementById("butn").removeAttribute("disabled");
return alert("游戏结束");
}
//如果蛇头没有碰到边界或蛇身,在地图上绘制蛇头
draw(n,"#00b7ee");
//如果蛇头吃到了食物(坐标相同)
if(n==food)
{
//随机在地图上产生一个新食物,新事物不能于蛇身子重合
//Math.random()是令系统随机选取大于等于 0.0 且小于 1.0 的伪随机 double 值
while(snake.indexOf(food=~~(Math.random()*400))>=0);
//绘制食物
draw(food,"yellow");
}
//如果蛇头没有吃到食物
else
{
//将蛇尾元素删除并且根据删除的坐标绘制为地图块的颜色
draw(snake.pop(),"#313131");
}
//每100毫秒重复执行一次该函数
setTimeout(arguments.callee,speed);
}
//添加键盘事件
document.onkeydown=function(e)
{
//如果蛇当前横着走,当键盘输入up时,将蛇头方向改为向上,输入down时将蛇头方向改为向下
if((direction==1||direction==-1)&&(snake[0]-snake[1]==1||snake[0]-snake[1]==-1))
{
if(e.keyCode==38) //上
direction=-20;
if(e.keyCode==40) //下
direction=20;
}
//如果蛇当前竖着走,当键盘输入left时向左,right时向右
if((direction==20||direction==-20)&&(snake[0]-snake[1]==20||snake[0]-snake[1]==-20))
{
if(e.keyCode==39) //右
direction=1;
if(e.keyCode==37) //左
direction=-1;
}
}
</script>
<div>
<button id="butn" type="button" onclick="run()">开始游戏</button>
</div>
</body>
</html>
相关属性与方法
<canvas id="canvas" width="300" height="300" style="background-color:write">
var box=document.getElementById('canv').getContext('2d'); //两种方法写在一起
box.fillStyle = 'green'; //绘制矩形的颜色
box.fillRect(10, 10, 150, 100); //描绘矩形的位置及大小
canvas 元素
直接在 html 标签中设置 width 和 height 属性并使用 JavaScript 来指定画布背景为白色
.getElementById()
方法
获取 < canvas > 标签的引用
.getContext()
方法
渲染图像(目前只有 2d)
fillStyle
属性
让长方形变成绿色
.fillRect()
方法
将它的左上角放在(10, 10),把它的大小设置成宽150高100
补充
JavaScript中 ~~ 的使用方法
~~ 代表双非按位取反运算符
对于正数,它向下取整;对于负数,向上取整;对于非数字,取值为 0
~~0; // => 0
~~null; // => 0
~~{}; // => 0
~~false; // => 0
~~true; // => 1
~~1.9; // => 1
~~-1.9; // => -1
JavaScript中 .indexOf
方法
返回 某个指定的字符串值在字符串中首次出现的位置 或 元素在列表中首次出现的位置,若找不到则返回 -1
var str="Hello world!"
document.write(str.indexOf("Hello") + "<br/>")
document.write(str.indexOf("World") + "<br/>")
document.write(str.indexOf("world"))
output:
0
-1
6
解决bug
问题: 若 run 函数一轮循环接收多个键位会导致游戏强制结束
解决方法: 调整键盘事件仅当 snake 数组前两个元素相邻时(矩形紧挨时)才能执行,而只有 run 函数结束上一轮循环时,snake 数组才开始接收键位,也就是一轮循环,只能接收一个键位
原:
if(direction==1||direction==-1)
if(direction==20||direction==-20)
改:
if((direction==1||direction==-1)&&(snake[0]-snake[1]==1||snake[0]-snake[1]==-1))
if((direction==20||direction==-20)&&(snake[0]-snake[1]==20||snake[0]-snake[1]==-20))
原本我还想加入一些有趣的玩法,奈何实力不足,我想等我有能力了再重新加入这些玩法,想加入的玩法如下:
- 随着时间贪吃蛇的速度会减少,但吃了一个食物速度会增加 一点,相当于竞速模式,获胜的条件即速度到达某个值 或 长度大于某个值(这个我本可以实现,但无法具体在网页上显示具体数值就,所以还是不加了)
- 添加暂停按钮(最好加个快捷键)
- 失败与胜利的弹出窗口改变样式
- 贪吃蛇初始位置随机(本代码是静态生成,但食物是动态生成的)
- 颜色随着位置的改变而改变(七彩蛇)