效果截图
实现原理
通过div布局来实现贪吃蛇小游戏,html+JavaScript实现, 通过方向键的上下左右实现蛇的移动
首先,地图为一个二维数组 Map[*][*]
蛇的坐标分为X轴和Y轴 即 行(H) 与 列(L),且分别用 SnakeH 和 SnakeL 两个一维数组来存储
并且都以SnakeH[0] 和 SnakeL[0]作为蛇头进行移动
食物的坐标分为X轴和Y轴,用 foodX 和 foodY 来记录食物坐标
首先通过双层for循环生成存储地图用的二维数组
然后通过循环使用 document.createElement("div"); 在一个div中添加多个子元素
一共添加800个子元素,填充至父div中.
然后通过css设置,地图div的背景颜色为肉色,蛇身的div背景颜色为绿色,食物为红色.
通过改变div颜色来实现物体显示
其中还使用了 window.onkeydown = function( ) 方法来获取键盘输入按键
还使用了
定时器 (要执行的代码或方法名,间隔的时间(毫秒));
var hh = setInterval("move()",200);
使其每0.2秒就调用一次移动方法.
下面是全部代码!
代码分析
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贪吃蛇</title>
<style type="text/css">
h1{
font-family: 楷体;
text-align: center;
color: #9555af;
}
#father{
width: 800px;
height: 400px;
border: 1px solid black;
margin: 0 auto;
}
.baby{
height: 18px;
width: 18px;
border: 1px solid black;
background-color: bisque;
float: left;
}
.snake{
height: 18px;
width: 18px;
border: 1px solid black;
background-color: green;
float: left;
}
.food{
height: 18px;
width: 18px;
border: 1px solid black;
background-color: red;
float: left;
}
#buttn{
width: 70px;
height: auto;
border: 1px solid transparent;
margin: 0 auto;
margin-top: 50px;
}
button {
/*清除button默认的样式*/
padding: 0;
border: none;
font: inherit;
color: inherit;
background-color: transparent;
cursor: pointer;
}
.btn {
/* 默认为button 但是在<a>上依然有效 */
display: inline-block;
text-align: center;
text-decoration: none;
/* 创造上下间距一定的空间 */
margin: 2px 0;
/* border透明 (当鼠标悬停时上色) */
border: solid 1px transparent;
border-radius: 4px;
/* padding大小与字体大小相关 (no width/height) */
padding: 0.5em 1em;
/* 确保字体颜色和背景色有足够区分度! */
color: #ffffff;
background-color: #9555af;
}
</style>
</head>
<body>
<h1>网页版贪吃蛇</h1>
<div id="father"></div>
<div id="buttn">
<button type="button" class="btn" onclick="starGame()">开始</button>
</div>
<script type="text/javascript">
//全局变量
var Map = new Array(); // 地图数组
var snakeH = [10,10,10,10,10]; //行
var snakeL = [27,28,29,30,31];//列
var foodX = 0;
var foodY = 0
var snakeLength = 5; //蛇的长度
function starMap(){//用于产生初始地图与资源
for (var i=0; i<20; i++) {
Map[i] = Array();
for(var j=0; j<40; j++){
var div2 = document.createElement("div");
div2.className = "baby";
Map[i][j] = document.getElementsByTagName("div")[0].appendChild(div2);
}
}
}
function cleanMap(){//将地图全部变成肉色
for (var i=0; i<20; i++) {
for (var j=0; j<40; j++) {
Map[i][j].className="baby";
}
}
}
function showSnake(){
//初始蛇身长度为3,包括蛇头
for (var i=0; i<snakeLength; i++) {
console.log("蛇的坐标:"+snakeH[i]+","+snakeL[i]+";");
}
for (var i=0; i<snakeLength; i++) {
Map[snakeH[i]][snakeL[i]].className="snake";
}
}
function creayFood(){
//随机生成食物坐标
foodX = parseInt(RandoMath(0,20));
foodY = parseInt(RandoMath(0,40));
//如果食物生成到了蛇身,则重新生成食物
for(var i=0; i<snakeLength; i++){
if(snakeH[i]==foodX && snakeL[i]==foodY){
foodX = parseInt(RandoMath(0,20));
foodY = parseInt(RandoMath(0,40));
}
}
console.log("新的食物的坐标:"+foodX+","+foodY+"; ");
}
function showFood(){
Map[foodX][foodY].className="food";
}
function eatFood(){
//每次都记录下蛇身数组
var fSnakeH = snakeH;
var fSnakeL = snakeL;
//如果蛇头的位置等于食物的位置
if(snakeH[0] == foodX && snakeL[0] == foodY){
//记录食物的坐标
var fH = foodX;
var fL = foodY;
//将食物坐标放入蛇数组的第一位
snakeH[0] = fH;
snakeL[0] = fL;
for (var i=1; i<snakeLength; i++) {
snakeH[i] = fSnakeH[i];
snakeL[i] = fSnakeL[i];
}
snakeLength += 1;//蛇身长度加1
console.log("吃到了食物!");
//生成一个新食物
creayFood();
}else{
console.log("没有吃到食物!");
}
}
function death(){
if(snakeH[0] < 0 || snakeL[0] < 0){
console.log("你撞墙了!");
alert("你撞墙了! 你的分数为"+snakeLength);
location.reload();
}
if(snakeH[0] > 20 || snakeL[0] > 40){
console.log("你撞墙了!");
alert("你撞墙了! 你的分数为"+snakeLength);
location.reload();
}
for (var i=1; i<snakeLength; i++) {
if(snakeH[0] == snakeH[i] && snakeL[0] == snakeL[i]){
console.log("你自杀了!");
alert("你自杀了! 你的分数为"+snakeLength);
location.reload();
}
}
}
var zhi = 38;//默认开始方向向上走
var f = zhi;
window.onkeydown = function(e){
var ke = e.keyCode;
if(ke == 37 && zhi != 39){
zhi=ke;
f = zhi;
console.log(zhi);
}
if(ke === 38 && zhi != 40){
zhi=ke;
f = zhi;
console.log(zhi);
}
if(ke === 39 && zhi != 37){
zhi=ke;
f = zhi;
console.log(zhi);
}
if(ke === 40 && zhi != 38){
zhi=ke;
f = zhi;
console.log(zhi);
}
if(ke != 37 && ke != 38 && ke != 39 && ke != 40){
zhi = f;
}
}
function move(){
var flag1 = 0;
var flag2 = 0;
var flag3 = 0;
var flag4 = 0;
//方向键 ←为37 ↑ 38 → 39 ↓ 40
switch(zhi){
case 37:
flag1 = snakeL[0];
flag2 = snakeL[1];
flag3 = snakeH[0];
flag4 = snakeH[1];
snakeL[0] -= 1; //向左移动,蛇头的列发生变化,向左-1
break;
case 38:
flag1 = snakeL[0];
flag2 = snakeL[1];
flag3 = snakeH[0];
flag4 = snakeH[1];
snakeH[0] -= 1;//向上移动,蛇头的行发生变化,向上-1
break;
case 39:
flag1 = snakeL[0];
flag2 = snakeL[1];
flag3 = snakeH[0];
flag4 = snakeH[1];
snakeL[0] += 1; 向右移动,蛇头的列发生变化,向右+1
break;
case 40:
flag1 = snakeL[0];
flag2 = snakeL[1];
flag3 = snakeH[0];
flag4 = snakeH[1];
snakeH[0] += 1; 向下移动,蛇头的列发生变化,向下+1
break;
}
//蛇头坐标修改之后,再将除蛇头外的蛇身坐标全部向后交换
// *!!!* 这里的细节原理文章结尾会有解释
console.log("屁股的坐标:"+snakeH[snakeLength-1]+","+snakeL[snakeLength-1]+"; ");
for(var i=1; i<snakeLength; i+=2){
snakeL[i] = flag1;
flag1 = snakeL[i+1];
snakeH[i] = flag3;
flag3 = snakeH[i+1];
snakeL[i+1] = flag2;
flag2 = snakeL[i+2];
snakeH[i+1] = flag4;
flag4 = snakeH[i+2];
}
console.log("移动一次结束!");
eatFood();//判断是否吃到食物
death();//判断是否死亡
//每一次移动之后,都重新将所有div恢复成肉色,重新显示出蛇的最新位置,和食物的最新位置
cleanMap();
showSnake();
showFood();
}
function starGame(){//开始游戏
showSnake();
creayFood();
showFood();
//定时器 (要执行的代码,间隔的时间(毫秒))
var hh = setInterval("move()",200);
}
function RandoMath(Min,Max){//生成[Min,Max)之间的随机数
var num = Min + Math.random()*Max;
return num;
}
starMap();
</script>
</body>
</html>
总结
第250行代码解释: 数组中的蛇身坐标值交换
1.先将A[0]的值赋给flag1 , 再将A[1]的值赋给flag2
2.开始for循环,从下标1开始循环
for(var i=1; i<snakeLength; i+=2){ //由于两个flag,所以一次更改了两个数组节点的值,所以下标一次加2
snakeL[i] = flag1;
flag1 = snakeL[i+1]; // 在SnakeL[i+1]的值被flag2覆盖前,保存到flag1中去
snakeL[i+1] = flag2;
flag2 = snakeL[i+2];
}