JS 敲出(贪吃蛇 )

文章目录

    • (1) 游戏场景搭建
    • (2) 获取标签、准备数据
    • (3)贪吃蛇移动
    • (4) 控制贪吃蛇移动
    • (5) 随机生成食物
    • (6) 完成食物消化
    • (7) 边界判断
    • (8) 积分判断
    • (9) 暂停继续
  • 总结

(1) 游戏场景搭建

   给贪吃蛇一个场地布局
   
   代码如下:

<!DOCTYPE html>
<html lang="en">
  <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;
      }

      html,
      body {
        background: aliceblue;
      }

      #scene {
        position: relative;
        margin: 50px auto;
        background-color: rgba(144, 196, 118, 0.362);
        width: 1000px;
        height: 500px;
        border: solid 1px #333;
        box-shadow: #000 0 0 3px;
      }
    </style>
  </head>
  <body>
    <div id="scene"></div>
  </body>
</html>

效果如下:
JS 敲出(贪吃蛇 )_第1张图片

(2) 获取标签、准备数据

   ① 创建贪吃蛇标签和样式
   
   代码如下:
<!DOCTYPE html>
<html lang="en">
  <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;
      }

      html,
      body {
        background: aliceblue;
      }

      #scene {
        position: relative;
        margin: 50px auto;
        background-color: rgba(144, 196, 118, 0.362);
        width: 1000px;
        height: 500px;
        border: solid 1px #333;
        box-shadow: #000 0 0 3px;
      }
      #head {
        width: 50px;
        height: 50px;
        border-radius: 30px;
        /* background: orangered; */
        position: absolute;
        left: 150px;
        top: 0;
      }
      #pause {
        position: absolute;
        width: 98px;
        height: 62px;
        background-color: rgba(86, 167, 167, 0.789);
        color: white;
        margin-left: 1300px;
        margin-top: 34px;
        font-size: 22px;
      }
      #pause:hover {
        background-color: rgba(77, 118, 118, 0.6);
      }
      p{
        position: absolute;
        left: 0;
        top: 0;
        width: 50px;
        height: 50px;
        background: #666;
        border-radius: 50%;
        background-color: aquamarine;
        border: solid 1px white;
      }
    </style>
  </head>
  <body>
    <div id="scene">
            <!-- 蛇头 -->
      <div id="head" style="left: 150px; top: 0">
        <img src="./img/head.png" alt="" width="50px" height="50px" />
      </div>
      <!-- 蛇身 -->
      <p style="left: 100px; top: 0"></p>
      <p style="left: 50px; top: 0"></p>
      <p style="left: 0px; top: 0"></p>
    </div>
  </body>
</html>

JS 敲出(贪吃蛇 )_第2张图片

② 获取标签,声明需要的变量

这里不做过多解释  代码中注释很详细
  window.onload = function () {
        // 封装获取DOM对象的函数
        function $(selector) {
          return document.querySelectorAll(selector);
        }

        // 闭包+自执行函数,实现贪吃蛇独立开发
        !(function () {
          // 声明变量,记录贪吃蛇数据
          var speedX = 50; // 水平移动速度
          var speedY = 0; // 垂直移动速度
          var score = 0; // 积分(吃掉一个食物,增加1分)

          var pauseX = 0; // 暂停时记录的X速度
          var pauseY = 0; // 暂停时记录的Y速度
          var pause = false; // 当前程序正在执行
          var pauseBtn = $("#pause")[0]; // 暂停按钮

          // 获取需要的标签
          var _scene = $("#scene")[0];
          var _head = $("#head")[0]; // 蛇头
          var _ps = $("p"); // 蛇身NodeList
          _ps = Array.from(_ps); // 将类数组-类型转换-> 数组

          var food; // 随机的食物

          // 蛇-移动计时器
          var snakeInterval;
          // 食物-计时器
          var foodInterval;

(3)贪吃蛇移动

 (3)贪吃蛇移动

 移动过程,模仿生活中毛毛虫移动方式;让蛇尾先动(下一个位置就是下一个p
 元素的位置)方便开发的时候记录移动过程

 代码如下:
    // 贪吃蛇移动的函数
          function move() {
            // 从尾部向前移动
            for (var i = _ps.length - 1; i > 0; i--) {
              // 让每个p元素,移动到前一个p元素的位置
              _ps[i].style.left = _ps[i - 1].style.left;
              _ps[i].style.top = _ps[i - 1].style.top;
            }

            // 第一个p元素跟随蛇头移动
            _ps[0].style.left = _head.style.left;
            _ps[0].style.top = _head.style.top;

            // 蛇头移动
            _head.style.left = _head.offsetLeft + speedX + "px";
            _head.style.top = _head.offsetTop + speedY + "px";


            snakeInterval = setInterval(function () {
              // 每隔1秒,移动一次
              move();
            }, 200);
        }

(4) 控制贪吃蛇移动

 用户按下键盘上方向键(或者任意自定义按键)控制贪吃蛇移动

 事件对象,通过用户键盘按键按下事件,获取到用户按键的  ascii  码

代码如下:


          // 控制用户按键的操作
          document.onkeydown = function (e) {
            // 获取事件对象
            var e = e || window.event;
            // e.keyCode 获取用户按键对应的ascii码
            // console.log("用户按下了什么键?", e.keyCode)
            switch (e.keyCode) {
              case 37: // 左
                speedX = -50;
                speedY = 0;
                break;
              case 38: // 上
                speedY = -50;
                speedX = 0;
                break;
              case 39: // 右
                speedX = 50;
                speedY = 0;
                break;
              case 40: // 下
                speedY = 50;
                speedX = 0;
                break;
            }
          };

(5) 随机生成食物

 食物,代码中就是一个 p标签 ,随机 x坐标、y坐标 生成并添加到场景中即可
 
注意:每个食物出现之后,如果没有被吃掉的情况下,不能生成新的食物

代码如下:


          // 随机产生食物的函数
          function randomFood() {
            // 随机x/y坐标
            var x = 50 * Math.floor(Math.random() * 20); // 1000
            var y = 50 * Math.floor(Math.random() * 10); // 500

            // 如果随机的坐标出现在蛇身上,需要重新执行函数重新生成坐标
            for (var i = 0; i < _ps.length; i++) {
              if (_ps[i].offsetLeft === x && _ps[i].offsetTop === y) {
                // 重新生成坐标并创建食物:递归
                return randomFood();
              }
            }

            // 创建食物 div 标签
            food = document.createElement("foodss");
            food.className = "food";
            food.style.backgroundColor =
              "#" + Math.random().toString(16).substr(2, 6);

            food.style.left = x + "px";
            food.style.top = y + "px";

            // 添加到游戏场景中
            _scene.appendChild(food);
          }
              // 随机产生食物
            foodInterval = setInterval(function () {
              if (!food) {
               // 如果没有食物出现,创建一个食物
                randomFood();
              }
            }, 500);
          }

(6) 完成食物消化

 贪吃蛇吃掉食物,就是将食物 p标签 追加到贪吃蛇的 p标签 中;将存放食物的
 
 变量 food 赋值为 null 表示食物被消化了

代码如下:

      // 吃掉食物的函数
          function eat() {
            if (food) {
              // 当蛇头的位置和食物的位置重合:吃掉
              if (
                _head.style.left === food.style.left &&
                _head.style.top === food.style.top
              ) {
                var _p = document.createElement("p");
                _p.style.backgroundColor = 
                food.style.backgroundColor;

                // 将食物置空:表示食物被吃掉了
                _scene.removeChild(food);
                food = null;

                // 将食物追加到贪吃蛇数组中
                _p.style.left = _ps[_ps.length - 1].style.left;
                _p.style.top = _ps[_ps.length - 1].style.top;
                _ps.push(_p);
                _scene.appendChild(_p);
              // 注意:吃掉食物的函数,需要在贪吃蛇移动的函数内部调用
                 function move() { 
                       ..... 
                    // 判断是否吃掉食物
                   eat() }
           
              }
            }
          }

(7) 边界判断

 贪吃蛇移动,能不能超出游戏场景;一旦越界说明游戏失败,所以只需要判断蛇
 头有没有越界即可!
 
 ① 不能超出游戏场景
// 边界判断
          function borderJudge() {
            // 判断蛇头是否出了场景
            if (
              _head.offsetLeft < 0 ||
              _head.offsetLeft > 950 ||
              _head.offsetTop < 0 ||
              _head.offsetTop > 450
            ) {
              // 停止贪吃蛇运动和随机食物
              clearInterval(snakeInterval);
              clearInterval(foodInterval);
              // 提示消息
              alert("你已经越界了,游戏结束");
              location.reload();
            }
 ② 蛇头不能进入自己身体
     // 蛇头是否进入自己身体
            for (var i = 0; i < _ps.length; i++) {
              if (
                _ps[i].style.left === _head.style.left &&
                _ps[i].style.top === _head.style.top
              ) {
                // 停止贪吃蛇运动和随机食物
                clearInterval(snakeInterval);
                clearInterval(foodInterval);
                // 提示消息
                alert("你吃掉自己的身体了,游戏结束");
                location.reload();
              }
            }
          }

(8) 积分判断

 我们后续可以通过积分的判断,完成用户等级提升等各种操作

 代码如下:
// 积分刷新
                var h1 = document.getElementsByTagName("h1")
                score += 10;
                h1[0].innerHTML = "Score:" +score;

(9) 暂停继续

用户游戏过程中,随时可以暂停游戏;然后也可以继续游戏

暂停:让当前贪吃蛇速度归0(记录原来的速度)

继续:让贪吃蛇速度还原(使用原来的速度重新赋值)

代码如下:


          // 暂停 和 恢复
          pauseBtn.onclick = function () {
            if (!pause) {
              // 游戏正在执行中
              pause = true;
              pauseX = speedX;
              pauseY = speedY;
              speedX = speedY = 0; // 暂停
              alert("主人,我已遵循指令对游戏进行了暂停");
              clearInterval(snakeInterval); // 清空计时器
              clearInterval(foodInterval); // 清空计时器
            } else {
              pause = false;
              speedX = pauseX;
              speedY = pauseY;
              play(); // 重新启动恢复游戏
            }
          };

效果如下:

暂停显示我用弹窗表示了(应添加点击效果遮罩背景更为美观)JS 敲出(贪吃蛇 )_第3张图片

总结

完整代码如下:

<!DOCTYPE html>
<html lang="zh">
  <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;
      }

      html,
      body {
        background: aliceblue;
      }

      #scene {
        position: relative;
        margin: 50px auto;
        background-color: rgba(139, 205, 106, 0.475);
        width: 1000px;
        height: 500px;
        border: solid 1px #333;
        box-shadow: #000 0 0 3px;
      }

      #head {
        width: 50px;
        height: 50px;
        border-radius: 30px;
        /* background: orangered; */
        position: absolute;
        left: 150px;
        top: 0;
      }

      p,
      .food {
        position: absolute;
        left: 0;
        top: 0;
        width: 50px;
        height: 50px;
        background: #666;
        border-radius: 50%;
        background-color: aquamarine;
        border: solid 1px white;
      }
      #pause {
        position: absolute;
        width: 98px;
        height: 62px;
        background-color: rgba(86, 167, 167, 0.789);
        color: white;
        margin-left: 1300px;
        margin-top: 34px;
        font-size: 22px;
      }
      #pause:hover {
        background-color: rgba(77, 118, 118, 0.6);
      }
      #score{
        position: absolute;
        width: 128px;
        height:62px;
        background-color: rgba(86, 167, 167, 0.789);
        color:white;
        margin-left: 1300px;
        margin-top: 125px;
        font-size: 22px;
        text-align: center;
        line-height: 62px;
      }

      p:nth-of-type(1){left: 0;}
    p:nth-of-type(2){left: 50px;}
    p:nth-of-type(3){left: 100px;}
    </style>
  </head>

  <body>
    <button id="pause">暂停</button>
    <h1 id="score">Score:0</h1>
    <!-- 游戏舞台 -->
    <div id="scene">
      <!-- 蛇头 -->
      <div id="head" style="left: 150px; top: 0">
        <img src="./img/head.png" alt="" width="50px" height="50px" />
      </div>
      <!-- 蛇身 -->
      <p style="left: 100px; top: 0"></p>
      <p style="left: 50px; top: 0"></p>
      <p style="left: 0px; top: 0"></p>
    </div>

    <script>
      window.onload = function () {
        // 封装获取DOM对象的函数
        function $(selector) {
          return document.querySelectorAll(selector);
        }

        // 闭包+自执行函数,实现贪吃蛇独立开发
        !(function () {
          // 声明变量,记录贪吃蛇数据
          var speedX = 50; // 水平移动速度
          var speedY = 0; // 垂直移动速度
          var score = 0; // 积分(吃掉一个食物,增加1分)

          var pauseX = 0; // 暂停时记录的X速度
          var pauseY = 0; // 暂停时记录的Y速度
          var pause = false; // 当前程序正在执行
          var pauseBtn = $("#pause")[0]; // 暂停按钮

          // 获取需要的标签
          var _scene = $("#scene")[0];
          var _head = $("#head")[0]; // 蛇头
          var _ps = $("p"); // 蛇身NodeList
          _ps = Array.from(_ps); // 将类数组-类型转换-> 数组

          var food; // 随机的食物

          // 蛇-移动计时器
          var snakeInterval;
          // 食物-计时器
          var foodInterval;

          // 贪吃蛇移动的函数
          function move() {
            // 从尾部向前移动
            for (var i = _ps.length - 1; i > 0; i--) {
              // 让每个p元素,移动到前一个p元素的位置
              _ps[i].style.left = _ps[i - 1].style.left;
              _ps[i].style.top = _ps[i - 1].style.top;
            }

            // 第一个p元素跟随蛇头移动
            _ps[0].style.left = _head.style.left;
            _ps[0].style.top = _head.style.top;

            // 蛇头移动
            _head.style.left = _head.offsetLeft + speedX + "px";
            _head.style.top = _head.offsetTop + speedY + "px";

            // 判断是否吃掉食物
            eat();
            // 判断边界
            borderJudge();
          }

          // 控制用户按键的操作
          document.onkeydown = function (e) {
            // 获取事件对象
            var e = e || window.event;
            // e.keyCode 获取用户按键对应的ascii码
            // console.log("用户按下了什么键?", e.keyCode)
            switch (e.keyCode) {
              case 37: // 左
                speedX = -50;
                speedY = 0;
                break;
              case 38: // 上
                speedY = -50;
                speedX = 0;
                break;
              case 39: // 右
                speedX = 50;
                speedY = 0;
                break;
              case 40: // 下
                speedY = 50;
                speedX = 0;
                break;
            }
          };

          // 吃掉食物的函数
          function eat() {
            if (food) {
              // 当蛇头的位置和食物的位置重合:吃掉
              if (
                _head.style.left === food.style.left &&
                _head.style.top === food.style.top
              ) {
                var _p = document.createElement("p");
                _p.style.backgroundColor = food.style.backgroundColor;

                // 将食物置空:表示食物被吃掉了
                _scene.removeChild(food);
                food = null;

                // 将食物追加到贪吃蛇数组中
                _p.style.left = _ps[_ps.length - 1].style.left;
                _p.style.top = _ps[_ps.length - 1].style.top;
                _ps.push(_p);
                _scene.appendChild(_p);

                // 积分刷新
                var h1 = document.getElementsByTagName("h1")
                score += 10;
                h1[0].innerHTML = "Score:" +score;

              }
            }
          }

          // 随机产生食物的函数
          function randomFood() {
            // 随机x/y坐标
            var x = 50 * Math.floor(Math.random() * 20); // 1000
            var y = 50 * Math.floor(Math.random() * 10); // 500

            // 如果随机的坐标出现在蛇身上,需要重新执行函数重新生成坐标
            for (var i = 0; i < _ps.length; i++) {
              if (_ps[i].offsetLeft === x && _ps[i].offsetTop === y) {
                // 重新生成坐标并创建食物:递归
                return randomFood();
              }
            }

            // 创建食物 div 标签
            food = document.createElement("foodss");
            food.className = "food";
            food.style.backgroundColor =
              "#" + Math.random().toString(16).substr(2, 6);

            food.style.left = x + "px";
            food.style.top = y + "px";

            // 添加到游戏场景中
            _scene.appendChild(food);
          }

          // 边界判断
          function borderJudge() {
            // 判断蛇头是否出了场景
            if (
              _head.offsetLeft < 0 ||
              _head.offsetLeft > 950 ||
              _head.offsetTop < 0 ||
              _head.offsetTop > 450
            ) {
              // 停止贪吃蛇运动和随机食物
              clearInterval(snakeInterval);
              clearInterval(foodInterval);
              // 提示消息
              alert("你已经越界了,游戏结束");
              location.reload();
            }

            // 蛇头是否进入自己身体
            for (var i = 0; i < _ps.length; i++) {
              if (
                _ps[i].style.left === _head.style.left &&
                _ps[i].style.top === _head.style.top
              ) {
                // 停止贪吃蛇运动和随机食物
                clearInterval(snakeInterval);
                clearInterval(foodInterval);
                // 提示消息
                alert("你吃掉自己的身体了,游戏结束");
                location.reload();
              }
            }
          }

          // 暂停 和 恢复
          pauseBtn.onclick = function () {
            if (!pause) {
              // 游戏正在执行中
              pause = true;
              pauseX = speedX;
              pauseY = speedY;
              speedX = speedY = 0; // 暂停
              alert("主人,我已遵循指令对游戏进行了暂停");
              clearInterval(snakeInterval); // 清空计时器
              clearInterval(foodInterval); // 清空计时器
            } else {
              pause = false;
              speedX = pauseX;
              speedY = pauseY;
              play(); // 重新启动恢复游戏
            }
          };

          /**游戏开始的函数 */
          function play() {
            // 移动贪吃蛇
            snakeInterval = setInterval(function () {
              // 每隔1秒,移动一次
              move();
            }, 200);

            // 随机产生食物
            foodInterval = setInterval(function () {
              if (!food) {
                // 如果没有食物出现,创建一个食物
                randomFood();
              }
            }, 500);
          }

          // 开始游戏
          play();
        })();
      };
    </script>
  </body>
</html>

整体效果如下:
JS 敲出(贪吃蛇 )_第4张图片

多加练习,熟练函数应用!多写几个案例!

你可能感兴趣的:(javascript,css,前端)