Bootstrap

基于html/CSS/js实现贪吃蛇(后续补理论知识)

实现效果
在这里插入图片描述
1、CSS文件
base.css文件

html ,body{/*逗号表示并集选择器*/
width: 100%;
}
.map{
        width: 90px;
        height: 90px;
        margin: 50px auto;
        background-color:#ccc;
}
.map ul{
        height: 30px;
}
.map ul li{
        width: 28px;
        height: 28px;
        border: 1px solid #af0;
        float: left;
}
.map ul li.snake{
       /*交集选择器*/ 
background-color: blue;


}
.map ul li.egg{
        background-color: crimson;
}

reset.css文件

* {
        /*去掉所有标签的内外边距*/
        padding:0;
        margin:0;


}
ul{
        list-style: none;
}

2、JS文件
msk.js

// 1.0 获取相关元素
var box = document.querySelector(".msk");
var tips = document.querySelector(".tips");
var restartBtn = document.querySelector(".restart_btn");
var quxiaoBtn = document.querySelector(".quxiao_btn");

// 2.0 封装一个方法
function show(str , callback){
    // 2.0.1 显示msk盒子
    box.style.display = "block";
    // 2.0.2 设置提示语
    tips.innerHTML = str;
    // 2.0.3 再玩一次
    restartBtn.onclick = function(){
        // 2.0.6 隐藏msk盒子
        box.style.display = "none";
        // 2.0.4 
        if(callback){ //判断是否存在回调函数
            callback();//是  调用
        }
    }
    // 2.0.5 隐藏msk盒子
    quxiaoBtn.onclick = function(){
        // 2.0.6 隐藏msk盒子
        box.style.display = "none";
    }
}

snake.js


/*
//console.log("text")
//定义变量
//获取.map这个标签
var ele = document.querySelector('.map');
var resultEle = document.querySelector(".result span")
//定义多少行多少列
var rowCount = 15;
var colCount = 15;
//定义列的大小
var space = 30;
//设置map的宽度和高度
ele.style.width = colCount * space + "px";
ele.style.height = rowCount * space + "px";
//定义一个 数组,记录所有的li标签
var ali = [];
//循环 创建ul标签,没循环一次,创建一个标签

for (var i = 0; i < rowCount; i++) {
        var ulCreate = document.createElement("ul");
        //定义小数组,记录每一行有多少个标签
        var rowArr = [];
        //循环创建li标签
        for (var j = 0; j < colCount; j++) {
                //没循环一次,创建一个li标签
                var liCreate = document.createElement("li");
                //往数组(小)里面,添加一个li
                rowArr.push(liCreate);
                ulCreate.appendChild(liCreate);



        }
        //往map标签(ele)添加ulCreate标签
        ele.appendChild(ulCreate);
        //把小数组添加到大数组里面去
        ali.push(rowArr);

}
//绘制蛇(代表蛇的li标签,类名snake)
//定义数组
console.log(ali)
var snakeBody = [];
for (var k = 0; k < 3; k++) {
        ali[0][k].className = "snake";
        snakeBody.push(ali[0][k]);



}
//绘制食物
console.log(snakeBody)
var eggX = 0;
var eggY = 0;
//产生随机数的函数
function rd(max, min) {
        //产生0-10之间的随机数,带小数点
        //产生指定范围的随机数,带小数点
        return Math.floor(Math.random() * (max - min) + min);
        //Math.random()*10

}
//产生食物的坐标
function createFood() {
        eggX = rd(colCount - 1, 0);
        //创建行
        eggY = rd(rowCount - 1, 0);
        if (ali[eggY][eggX].className == "snake") {
                createFood();
        }
        else {
                ali[eggY][eggX].className = "egg";
        }

}
createFood();

//分数的变量
//1、控制蛇的移动方向 蛇移动的坐标(默认)
var x = 2;
var y = 0;
//2、移动方向
var direction = "right";
//3、boolean
var isChange = false;
//4、定时器函数
var timer = setInterval(move, 200);
//5、编写移动的逻辑
function move() {
        //控制流语句
        switch (direction) {
                //向右边
                case "right":
                        x++;
                        break;
                case "left":
                        x--;
                        break;
                case "down":
                        y++;
                        break;
                case "up":
                        y--;
                        break;


        }
        //判断蛇移动的范围
        if (x < 0 || x > (colCount - 1) || y < 0 || y > (rowCount - 1)) {
                //提示
                alert("游戏结束!")
                //停止定时器函数
                clearInterval(timer)
                return;

        }
        //判断蛇吃到食物的时候
        if (eggX == x && eggY == y) {
                //设置食物的背景色
                ali[eggY][eggX].className = "snake";
                //把食物的标签添加到snakebody
                snakeBody.push(ali[eggY][eggX]);
                createFood();
                //加分
                score = score + 1;
                //显示分数
                resultEle.innerHTML = score;


        }
        else {
                //设置蛇数组的第一个元素的类名
                snakeBody[0].className = "";
                //删除蛇数组的第一个元素
                snakeBody.shift();
                //添加下一个元素
                snakeBody.push(ali[y][x]);
                //给下一个元素设置类名
                ali[y][x].className = "snake";

        }

        //ali[y][x].className = "snake";
}

//通过键盘事件改变
document.onkeydown = function (evt) {
        //防止连续快速按键
        if (isChange) {
                return;
        }
        //如果蛇正朝着,右边走,按左边键盘无效
        var code = evt.keyCode;
        if (direction == "right" && code == 37) {
                return;
        }
        if (direction == "left" && code == 39) {
                return;
        }
        if (direction == "down" && code == 38) {
                return;
        }
        if (direction == "up" && code == 40) {
                return;//终止代码
        }
        switch (code) {
                case 40:
                        direction = "down";
                        isChange = true;
                        break;
                case 38:
                        direction = "up";
                        isChange = true;
                        break;
                case 39:
                        direction = "right";
                        isChange = true;
                        break;
                case 37:
                        direction = "left";
                        isChange = true;
                        break;

        }
        //延迟200ms
        setTimeout(function () {
                isChange = false;
        }, 200)
}
*/
//console.log("test")// 检查代码
// 1.0 定义变量
// 1.0.1 获取.map这个标签
var ele = document.querySelector('.map');
var resultEle = document.querySelector(".result span");

// 1.0.2 定义多少行
var rowCount = 15;
// 2.0.3 定义多少列
var colCount = 15;
// 2.0.4 定义列的大小
var space = 30;
// 2.0.5 设置map的宽度高度
ele.style.width = colCount * space + "px";
ele.style.height = rowCount * space + "px";
// 3.0 定义数组(大)记录所有的li标签
var aLi = [];
// 4.0 循环 创建ul标签(行)
for(var i = 0 ; i < rowCount; i++){
    // 4.0.1每循环一次 创建一个ul标签
    var ulCreate = document.createElement("ul")
    // 4.0.2定义数组(小)记录每一行有多少个li标签
    var rowArr = [];
    // 4.0.3循环  创建li标签(列)
    for(var j = 0 ; j < colCount ; j++){
        //4.0.4 每循环一次 创建一个li标签
        var liCreate = document.createElement("li");
        //4.0.5往数组(小)添加li标签
        rowArr.push(liCreate)
        //4.0.6往ulCreate标签 添加li标签
        ulCreate.appendChild(liCreate);
    }
    // 4.0.7往map标签(ele)添加ulCreate标签
    ele.appendChild(ulCreate);
    // 4.0.8 把小数组(rowArr) 添加到大数组(aLi)
    aLi.push(rowArr);
}
console.log(aLi)
// 5.0 绘制蛇(代表蛇的li标签  类名 snake)
// 5.0.1 定义数组(蛇)
var snakeBody = [];
// 5.0.2 默认第一行前三个li标签为蛇
for(var k = 0 ; k < 3 ; k++){
    // 5.0.3 设置第一行前三个li标签 添加类名 snake
    aLi[0][k].className = "snake";
    // 5.0.4 往蛇数组添加 第一行前三个li标签
    snakeBody.push( aLi[0][k]);
}
console.log(snakeBody)

// 6.0 绘制食物
// 6.0.1 定义食物的x坐标
var eggX = 0;
var eggY = 0;
// 6.0.2 产生随机数的函数
function rd(max , min){
    // 6.0.3 处理随机数的逻辑
    // Math.random()*10   产生0-10之间随机数 带小数点
    // Math.random()*10 + 10  产生10-20之间随机数 带小数点
    // Math.random()*(max - min) + min ; 产生指定范围的随机数 带小数点
    // Math.floor(); 向下取整  1.123123 => 1
    return Math.floor(Math.random()*(max-min)+min);
}
// 6.0.3 产生食物的坐标
function createFood(){
    // 6.0.4 创建 列 x  colCount 
    eggX = rd(colCount-1,0);
    // 6.0.5 创建 行 y  rowCount
    eggY = rd(rowCount-1,0);
    // 6.0.6 判断创建的坐标对应的li标签 是否带有 snake 类名
    if(aLi[eggY][eggX].className == "snake"){
        // 6.0.7 重新创建食物
        createFood();
    }else {
        // 6.0.7 设置食物的类名 egg
        aLi[eggY][eggX].className = "egg";
    }
}
// 6.0.8 调用创建食物的函数
createFood();

// 9.0 定义分数的变量
var score = 0;
// 7.0 控制蛇移动的方向
// 7.0.1 蛇移动的x坐标 和 y 坐标 (默认) 
var x = 2;
var y = 0;
// 7.0.2 移动方向
var direction = "right";
// 7.0.3 布尔值
var isChange = false;
// 7.0.4 定时器函数
var timer = setInterval(move, 200);//1000毫秒 = 1秒
// 7.0.5 编写移动的逻辑
function move(){
    // 7.0.6 控制流语句
    switch(direction){
        case "right": // 向右
                x++;
            break ;
        case "left":  // 向左
                x--;
            break ;
        case "down":  // 向下
                y++;
            break;
        case "up":    // 向上
                y--;
            break;
    }

    // 7.0.6.1 判断蛇移动的范围 
    if(x < 0 || x > (colCount-1) || y < 0 ||y > (rowCount-1)){
        //alert("游戏结束! ");//提示
        // 7.0.6.2 调用show方法
        show("游戏结束! " ,function(){
            // 7.0.6.3 分数重新计算
            score = 0;
            // 7.0.6.4 继续游戏(-)
            // timer = setInterval(move,200);
            // 刷新页面  继续游戏
            window.location.reload();
        })

        clearInterval(timer)//停止定时器函数
        return ; //终止代码
    }

    // 7.0.8 判断蛇吃到食物的时候
    if(eggX == x && eggY == y){
        // 7.0.9 设置食物的背景色
        aLi[eggY][eggX].className = "snake";
        // 7.0.10 把食物的标签添加到 snakeBody 
        snakeBody.push(aLi[eggY][eggX]);
        // 7.0.11 重新创建食物
        createFood();
        // 7.0.12 记录分数
        // score+=1;
        score = score + 1;
        // 7.0.17 显示分数
        resultEle.innerHTML = score;
    }else {
        // 7.0.13 设置蛇数组的第一个元素类名
        snakeBody[0].className = "";
        // 7.0.14 删除蛇数组第一个元素
        snakeBody.shift();
        // 7.0.15 添加下一个元素
        snakeBody.push(aLi[y][x]);
        // 7.0.16 给下一个元素设置类名
        aLi[y][x].className = "snake";
    }

    // 测试 
    // aLi[y][x].className = "snake";

}

// 8.0 通过键盘事件改变  direction 的值
document.onkeydown = function(evt){

    // 8.0.4 防止连续快速按键
    if(isChange){
        return;//终止代码
    }
    
    // 8.0.1 键值码
    var code = evt.keyCode;
    // 8.0.3 移动的方向处理
    // 如果蛇正朝着 右边走 ,按左边按键无效
    if(direction == "right" && code == 37){
        return ;//终止代码
    }
    if(direction == "left" && code == 39){
        return ;//终止代码
    }
    if(direction == "down" && code == 38){
        return ;//终止代码
    }
    if(direction == "up" && code == 40){
        return ;//终止代码
    }


    // 8.0.2 根据keyCode 改变 direction 
    switch(code){
        case 40 : 
                direction = "down";
                isChange = true;
            break;
        case 38 : 
                direction = "up";
                isChange = true;
        break;
        case 39 : 
                direction = "right";
                isChange = true;
            break;
        case 37 : 
                direction = "left";
                isChange = true;
        break;
    }

    // 8.0.5 延迟200毫秒
    setTimeout(function(){
        isChange = false;
    },200)

    // 10. 拓展暂停(空格按键)  开始(S按键)
    // 暂停(空格按键)32 
    console.log(code)
    if(code == 32) {
        // 停止执行定时器函数
        clearInterval(timer);
        return;
    }
    // 开始(S按键) 
    if(code == 83){
        // 停止执行定时器函数(用定时器 , 先清除定时器)
        clearInterval(timer);
        // 继续执行定时器函数(继续游戏)
        timer = setInterval(move , 200);
    }


}



3、HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>蛇和蛋蛋的故事</title>
    <!-- 引入样式文件 -->
    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/base.css">
    <style>
        .result {
            width: 150px;
            height: 40px;
            background-color: #ccc;
            line-height: 40px;
            color: #fff;
            position: fixed;
            left: 0;
            bottom: 50px;
            z-index: 1000;
        }
        .result span {
            color: red;
        }

        .msk {
            width: 220px;
            height: 120px;
            background-color: #fff;
            border: 1px solid #ccc;
            /* 定位 */
            position: absolute;
            left: 50%;
            top: 50%;
            margin-left: -110px;
            margin-top: -60px;
            /* 内边距 */
            padding: 0 10px;
            /* 隐藏盒子 */
            display: none;
        }
        .msk p {
            width: 220px;
            height: 50px;
            line-height: 50px;
            text-align: center;
        }
        .msk p span {
            color: #666;
        }
        .msk .btn {
            height: 36px;
            line-height: 36px;
            text-align: center;
            cursor: pointer;
            padding: 0 15px;
            border-radius: 5px;
            font-size: 13px;
            margin-top: 20px;
        }
        .restart_btn {
            float: left;
            color: skyblue;
            border: 1px solid skyblue;
        }
        .quxiao_btn {
            float: left;
            color: red;
            border: 1px solid red;
            margin-left: 10px;
        }
    </style>
</head>
<body>
    <!-- 显示分数 -->
    <div class="result">当前分数 : <span>0</span> </div>
    <!-- 地图 -->
    <div class="map">
        <!-- 动态创建 -->
    </div>

    <!-- 弹窗 -->
    <div class="msk">
        <p><span class="tips"> xxx </span></p>
        <div class="btn restart_btn">再玩一次</div>
        <div class="btn quxiao_btn">取消</div>
    </div>
</body>
</html>

<!-- 遮罩层 -->
<script src="js/msk.js"></script>
<!-- 贪吃蛇 -->
<script src="js/snake.js"></script>
;