本文章仅个人进行学习归纳,代码均参考网络(已注明来源)并经过个人修改。
20行代码实现 未理解算法
原文章链接
常规代码实现 已掌握
原文章链接
穿墙型贪吃蛇代码实现 未看
原文章链接
个人理解:
- onkeydown 事件会在用户按下一个键盘按键时发生。
- ~~ 利用该符号进行的类型转换,转换成数字类型/整数
- (
function() {}
)在前面加上一个布尔运算符,就是表达式了,将执行后面的代码,也就合法实现调用
!function() {}()
setTimeout(arguments.callee, 230);
callee返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。
callee 属性的初始值就是正被执行的 Function 对象。这允许匿名的递归函数通过setTimeout函数暂停一段时间后执行代码,可以实现一些特殊的效果。在此处,实现的效果是随着数值的大小(230)贪吃蛇移动的速度也在变化。
<!DOCTYPE html>
<html>
<head>
<title>SnakeGame</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!-- canvas HTML5中定义图形的标签,比如图表和其他图像-->
<canvas id="can" width="400" height="400" style="background:Black"></canvas>
<script>
/*通过调用canvas对象的getContext()方法来获取绘图环境。
* getContext()方法只需要一个参数:绘图环境的类型。
* 在游戏中,我们使用2D类型的绘图环境。 */
var sn = [42, 41], dz = 43, fx = 1, n, ctx = document.getElementById("can").getContext("2d"); /*sn为开始位置*/
function draw(t, c) {
ctx.fillStyle = c;
// 使用fillStyle方法设置所绘图形的颜色;使用fillRect(x,y,width,height)方法增加蛇的长度
ctx.fillRect(t % 20 * 20 + 1, ~~(t / 20) * 20 + 1, 18, 18);
}
document.onkeydown = function(e) {
// keyCode键码值,上38、下40、左37、右39
fx = sn[1] - sn[0] == (n = [-1, -20, 1, 20][(e || event).keyCode - 37] || fx) ? fx : n
};
!function() {
// unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度
sn.unshift(n = sn[0] + fx);
if (sn.indexOf(n, 1) > 0 || n < 0 || n > 399 || fx == 1 && n % 20 == 0 || fx == -1 && n % 20 == 19){
return alert("GAME OVER");}
draw(n, "Lime");
if (n == dz) {
while (sn.indexOf(dz = ~~(Math.random() * 400)) >= 0);
draw(dz, "Pink");
} else
draw(sn.pop(), "Black");
/*callee返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。
* callee 属性的初始值就是正被执行的 Function 对象。这允许匿名的递归函数
* 通过setTimeout函数暂停一段时间后执行代码,可以实现一些特殊的效果
*/
setTimeout(arguments.callee, 230);
}();
</script>
</body>
</html>
//算法理解有难度,还没理解完算法,因此再参考另一个js写的贪吃蛇代码
个人理解:
- 后续补充
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>贪吃蛇游戏</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.wrap {
width: 600px;
margin: 0 auto;
position: relative;
}
p {
position: absolute;
left: 65%;
top: 10%;
}
h1 {
text-align: center;
margin-bottom: 20px;
}
#score {
text-align: center;
font-size: 20px;
}
#snake_map {
margin: 0 auto;
border: 1px solid skyblue;
}
/*行样式*/
.row {
height: 20px;
}
/*列样式*/
.col {
height: 20px;
width: 20px;
box-sizing: border-box;
border: 1px solid lightgray;
background: rgb(250, 250, 250);
float: left;
}
.activeSnake {
background: black;
}
.egg {
background: red;
}
#Pause {
margin-left: 18%;
border: 1px solid skyblue;
color: white;
background: skyblue;
width: 50px;
height: 30px;
margin-bottom: 10px;
border-radius: 5px;
}
#Start,#Refresh,#Speed {
border: 1px solid skyblue;
background: skyblue;
color: white;
width: 50px;
height: 30px;
border-radius: 5px;
margin-left: 15px;
}
</style>
</head>
<body>
<div class="wrap">
<h1>贪吃蛇游戏</h1>
<!-- 记录吃了多少个蛋 -->
<p style="font-size:20px;color:red"> score:<span id="score" style="color:black">0</span> </p>
<!-- 暂停按钮 -->
<input id="Pause" type="button" name="name" value="Pause">
<!-- 开始按钮 -->
<input id="Start" type="button" name="name" value="Start">
<!-- 刷新(重新开始游戏) -->
<input id="Refresh" type="button" name="name" value="Refresh">
<!-- 加速按钮 -->
<input id="Speed" type="button" name="name" value="Speed">
<!-- 贪吃蛇的行走路径地图 -->
<div id="snake_map">
</div>
</div>
</body>
<script type="text/javascript">
//获取分数标签
var score = document.getElementById('score');
// 获取路径地图标签
var map = document.getElementById('snake_map');
// 为了灵活的设置地图的大小,以下设置两个变量
// 用于存储行数和列数(即方格的个数)
var rowNumber = 25;// 行数
var columnNumber = 20;// 列数;
var mapWidth = columnNumber * 20 + 'px';// 地图的宽
var mapHeight = rowNumber * 20 + 'px';// 地图的高
map.style.width = mapWidth;
map.style.height = mapHeight;// 设置地图宽高
// 创建一个二维数组,用来记录地图上的所有div的位置
var snakeDIVPosition = [];
// 通过双层for循环来创建地图元素
for ( var i = 0; i < rowNumber; i++) {
// 创建行div
var rowDIV = document.createElement('div');
// 设置div样式
rowDIV.className = 'row';
// 将行div添加到路径地图map中
map.appendChild(rowDIV);
// 创建一个行级数组,用来存储当前行中的每个方块div
var rowArray = [];
for ( var j = 0; j < columnNumber; j++) {
// 创建每一行中的方块div
var columnDIV = document.createElement('div');
// 设置css样式
columnDIV.className = 'col';
// 将方块DIV添加到当前行中
rowDIV.appendChild(columnDIV);
// 同时将方块添加到行数组中
rowArray.push(columnDIV);
}
// 当前内层循环结束,将行数组添加到二维数组中
snakeDIVPosition.push(rowArray);
}
// 创建蛇模型
// 创建一个一维数组,用来存储蛇身所占的div
var snake = [];
// 固定蛇身起始长度为3个div
for ( var i = 0; i < 3; i++) {
// 为蛇身设置不同颜色的div
snakeDIVPosition[0][i].className = 'col activeSnake';
// 存储在蛇身数组中
snake[i] = snakeDIVPosition[0][i];
}
// 定义变量来控制蛇
var x = 2;
var y = 0;// 蛇头的起始位置偏移量
var scoreCount = 0;// 分数计数器,即吃了多少个蛋
var eggX = 0;// 记录蛋所在的行位置
var eggY = 0;// 记录蛋所在的列位置;
var direction = 'right';// 记录蛇移动的方向,初始为向右
var changeDir = true;// 判断是否需要改变蛇的移动方向
var delayTimer = null;// 延迟定时器
// 添加键盘事件监听方向键来改变蛇的移动方向
document.onkeydown = function(event) {
// 先判断是否需要改变方向,true表示需要,false表示不需要
if (!changeDir) {
return;// return空表示直接结束函数,后续代码不执行
}
event = event || window.event;
// 为了合理处理蛇的移动,需要判断蛇头和蛇身
// 假设蛇向右移动,点方向键左,右键都不需要做出响应
if (direction == 'right' && event.keyCode == 37) {
return;// 终止事件执行
}
if (direction == 'left' && event.keyCode == 39) {
return;
}
if (direction == 'up' && event.keyCode == 40) {
return;
}
if (direction == 'down' && event.keyCode == 38) {
return;
}
// 我们通过keyCode确定蛇要移动的方向
switch (event.keyCode) {
case 37:
direction = 'left';// 向左
break;
case 38:
direction = 'up';// 向上;
break;
case 39:
direction = 'right';// 向右
break;
case 40:
direction = 'down';// 向下
break;
}
changeDir = false;
delayTimer = setTimeout(function() {
// 设置是否需要改变方向
changeDir = true;
}, 300);
};
// 开始设置蛇移动逻辑
// 蛇移动函数
function snakeMove() {
// 根据上面设置的方向来设置蛇头的位置
switch (direction) {
case 'left':
x--;
break;
case 'right':
x++;
break;
case 'up':
y--;
break;
case 'down':
y++;
break;
};
// 判断是否游戏结束
if (x < 0 || y < 0 || x >= columnNumber || y >= rowNumber) {
alert('Game Over!!!');
// 结束蛇移动的定时器
clearInterval(moveTimer);
return;// 终止键盘事件;
}
// 如果蛇吃到自己,也要结束游戏
for ( var i = 0; i < snake.length; i++) {
// 将此时蛇头移动后的位置与之前左右的组成蛇的div的位置进行比较,如果相同则说明吃到自己,游戏结束
if (snake[i] == snakeDIVPosition[y][x]) {
alert('Game over!!!');
clearInterval(moveTimer);
return;
};
}
// 判断蛇头移动的位置是否有蛋
if (eggX == x && eggY == y) {
snakeDIVPosition[eggY][eggX].className = 'col activeSnake';
snake.push(snakeDIVPosition[eggY][eggX]);// 加入蛇身
scoreCount++;// 记录分数
// 更新当前的分数
score.innerHTML = scoreCount;
// 随机产生一个新的蛋
createNewEgg();
} else {
// 设置蛇碰不到蛋的逻辑
// 让蛇移动
// 蛇尾去掉蛇自身的颜色,变成格子的颜色
snake[0].className = 'col';
// 将蛇尾div从数组中移除
snake.shift();
// 定位到的新的蛇头加入到蛇数组中
snakeDIVPosition[y][x].className = 'col activeSnake';
snake.push(snakeDIVPosition[y][x]);
};
};
var moveTimer = setInterval('snakeMove()', 300);
// 定义一个生成min,max之间的随机数函数
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
function createNewEgg() {
// 随机出新的egg的下标的x和y值
eggX = random(0, columnNumber - 1);
eggY = random(0, rowNumber - 1);
// 判断如果随机产生的蛋与蛇身重合,就重新随机产生一个蛋
if (snakeDIVPosition[eggY][eggX].className == 'col activeSnake') {
createNewEgg();// 重新随机新的egg
} else {
snakeDIVPosition[eggY][eggX].className = 'col egg';
}
};
createNewEgg();// 在游戏开始的时候生成新的egg
var pause = document.getElementById('Pause');
var start = document.getElementById('Start');
var refresh = document.getElementById('Refresh');
var speed = document.getElementById('Speed');
// 添加暂停按钮
pause.onclick = function() {
clearInterval(moveTimer);
};
// 添加开始按钮
start.onclick = function() {
clearInterval(moveTimer);
moveTimer = setInterval('snakeMove()', speed1);
};
// 添加刷新按钮
refresh.onclick = function() {
window.location.reload();
};
// 添加加速按钮
var speed1 = 300;
speed.onclick = function() {
speed1 -= 20;
clearInterval(moveTimer);
moveTimer = setInterval('snakeMove()', speed1);
};
</script>
</html>
穿墙型贪吃蛇,代码如下,其中蛇头和蛇身颜色不同(方便理解):
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
/*第一步:创建地图:*/
var map;
//封装地图的类
function Map(){
//设置地图的相关属性
this.width=1200;
this.height=600;
this.bgcolor="black";
//居中的属性
this.margin="0 auto";
//封装接收地图对象的属性
this._map=null;
//封装方法来实现dom元素的创建
this.createMap=function (){
//创建dom元素
if(this._map==null)
{
this._map=document.createElement("div");
this._map.style.width=this.width+"px";
this._map.style.height=this.height+"px";
this._map.style.position="relative";
this._map.style.margin=this.margin;
this._map.style.backgroundColor=this.bgcolor;
document.body.appendChild(this._map);
}
}
}
var snack;
function Snack(){
this.width=30;
this.height=30;
//控制方向的
this.direct="right";
//封装蛇的身子
this.snackbody=[[3,1,"blue",null],[2,1,"white",null],[1,1,"white",null]];
//封装创建蛇的方法
this.createsnack=function (){
for(var i=0;i<this.snackbody.length;i++)
{
if(this.snackbody[i][3]==null)
{
//创建dom元素
this.snackbody[i][3]=document.createElement("div");
this.snackbody[i][3].style.width=this.width+"px";
this.snackbody[i][3].style.height=this.height+"px";
this.snackbody[i][3].style.backgroundColor=this.snackbody[i][2];
this.snackbody[i][3].style.position="absolute";
map._map.appendChild(this.snackbody[i][3]);
}
this.snackbody[i][3].style.left=this.snackbody[i][0]*this.width+"px";
this.snackbody[i][3].style.top=this.snackbody[i][1]*this.height+"px";
}
}
//封装蛇移动的方法
this.snackmove=function (){
var length=this.snackbody.length-1;
for(var i=length;i>0;i--)
{
this.snackbody[i][0]=this.snackbody[i-1][0];
this.snackbody[i][1]=this.snackbody[i-1][1];
}
//在xy传递之后让蛇头动
/*根据移动方向来确定想x,y++ --*/
switch (this.direct){
case "right":this.snackbody[0][0]+=1; break;
case "left":this.snackbody[0][0]-=1; break;
case "up":this.snackbody[0][1]-=1; break;
case "down":this.snackbody[0][1]+=1; break;
}
this.snackback();
this.snackCollider();
//去判断蛇头和食物是否坐标一致
if(this.snackbody[0][0]==food.x&&this.snackbody[0][1]==food.y)
{
//开始长身体
this.snackbody.push([
this.snackbody[this.snackbody.length-1][0],
this.snackbody[this.snackbody.length-1][1],
"white",
null
]);
//食物换位置
food.createfood();
}
//动态传递xy坐标之后 重新设置蛇的位置
this.createsnack();
}
//判断蛇是否穿墙
this.snackback=function (){
if(this.snackbody[0][0]>=40)
{
this.snackbody[0][0]=0;
}
if(this.snackbody[0][0]<0)
{
this.snackbody[0][0]=39;
}
if(this.snackbody[0][1]>=20)
{
this.snackbody[0][1]=0;
}
if(this.snackbody[0][1]<0)
{
this.snackbody[0][1]=19;
}
}
//判断是否自己撞自己
this.snackCollider=function (){
for(var i=1;i<this.snackbody.length;i++)
{
if(this.snackbody[0][0]==this.snackbody[i][0]&&this.snackbody[0][1]==this.snackbody[i][1])
{
clearInterval(time);
alert("撞死啦!");
}
}
}
}
var food;
function Food(){
this.width=30;
this.height=30;
//食物的属性坐标
this.x=0;
this.y=0;
this._food=null;
this.createfood=function (){
//设置随机值
this.x=Math.floor(Math.random()*40);
this.y=Math.floor(Math.random()*20);
if(this._food==null)
{
this._food=document.createElement("div");
this._food.style.width=this.width+"px";
this._food.style.height=this.height+"px";
this._food.style.position="absolute";
this._food.style.backgroundColor="yellow";
map._map.appendChild(this._food);
}
this._food.style.left=this.x*this.width+"px";
this._food.style.top=this.y*this.height+"px";
}
}
var time;
//在窗体加载完成里面去实例化对象
window.onload=function (){
map=new Map();
map.createMap();
snack=new Snack();
snack.createsnack();
time=setInterval("snack.snackmove()",100);
food=new Food();
food.createfood();
document.onkeydown=function (e){
/* 通过按键 控制蛇的移动方向*/
/*e.keyCode*/
switch (e.keyCode){
case 37: if(snack.direct!="right")snack.direct="left"; break;
case 38: if(snack.direct!="down") snack.direct="up";break;
case 39: if(snack.direct!="left")snack.direct="right";break;
case 40: if(snack.direct!="up")snack.direct="down";break;
}
}
}
</script>
</body>
</html>