JavaScript贪吃蛇游戏源码

蛇对象

属性:方向、一组蛇节(div,div,div)、地图、食物
方法:生成蛇,增加蛇头,计算新蛇头的位置,蛇移动

食物对象

属性:横向位置、纵向位置、div元素、地图
方法:随机位置

游戏对象

属性:蛇,食物 
方法:开始
<!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/index.css">
</head>
<body>
<div id="map"> 
    <!-- <div class="snake-body" style="left:60px;top:0"></div>
    <div class="snake-body" style="left:80px;top:0"></div>
    <div class="snake-head" style="left:100px;top:0"></div> --> 
    <!-- 
      【生成蛇的规律】
      生成蛇,其实本质上就是不断的增加新蛇头。
      若没有蛇头,则创建一个新蛇头,设置位置为 0,0
      若有蛇头,则先把原有的蛇头变为身体,再添加新的蛇头。并且控制新蛇头的位置,在旧蛇头的基础上计算新蛇头的位置(根据方向来计算)。
     -->

     <!-- 
       【蛇移动的规律】
       把蛇的最后一节取出来,变为蛇头。
       旧的蛇头变为身体
       把最后一节添加到最前面,设置新蛇头的位置
      -->
  </div>
  <!-- 在这里压缩的目的是减少文件体积,合并的目的是减少请求次数。 这样可以提高程序的网页的访问速度。 -->
  <script src="js/all.js" ></script>

  <!-- 使用食物对象 -->
  <script>
    // 获取页面上的地图元素
    var map = document.querySelector('#map'); 
    // 创建了一个食物对象
    // var food1 = new Food(map);
    // // 食物随机一下
    // food1.randomLoaction();

   var game = new Game(map);
   game.start();

  </script>
</body>
</html>
/* 地图 */
#map {
 position: relative;
 margin: 0 auto;
 width: 900px;
 height: 600px;
 background-color: #1f575c;
 box-shadow: 0px 0px 50px 20px green;
}
/* 蛇头、蛇身体、食物基本样式 */
.snake-head,
.snake-body,
.food {
   position: absolute;
   width: 18px;
   height: 18px;
   border: dotted 1px black;
   /* border-radius: 17px; */
}
/* 蛇的身体 */
.snake-body {
   background: pink;
}
/* 蛇头样式 */
.snake-head {
   background-color: red;    
}
/* 食物 */
.food {
   background-color: #00ff00;    
}

all.js

function Food(m) {
   this.x = 0;
   this.y = 0;
   this.div = document.createElement("div");
   this.div.className = "food";
   this.map = m;
   this.map.appendChild(this.div)
}

Food.prototype.randomLoaction = function () {
   var maxX = 900 / 20 - 1;
   var maxY = 600 / 20 - 1;
   var indexX = getIntNum(0, maxX);
   var indexY = getIntNum(0, maxY);
   this.x = indexX * 20;
   this.y = indexY * 20;
   this.div.style.left = this.x + "px";
   this.div.style.top = this.y + "px"
};

function getIntNum(min, max) {
   var num = parseInt(Math.random() * (max - min + 1) + min);
   return num
};

function Snake(m, f) {
   this.direction = "right";
   this.bodys = [];
   this.map = m;
   this.food = f;
   this.createBodys()
}

Snake.prototype.createBodys = function () {
   for (var i = 0; i < 3; i++) {
       this.insertNewHead()
   }
};
Snake.prototype.insertNewHead = function () {
   var newHead = document.createElement("div");
   newHead.className = "snake-head";
   var location = this.getNewHeadLoaction();
   newHead.style.left = location.left + "px";
   newHead.style.top = location.top + "px";
   this.map.appendChild(newHead);
   var oldHead = this.bodys[0];
   if (oldHead != undefined) {
       oldHead.className = "snake-body"
   }
   this.bodys.unshift(newHead)
};
Snake.prototype.getNewHeadLoaction = function () {
   var x = 0;
   y = 0;
   var oldHead = this.bodys[0];
   if (oldHead == undefined) {
       return {left: x, top: y}
   }
   x = oldHead.offsetLeft;
   y = oldHead.offsetTop;
   switch (this.direction) {
       case"left":
           x = x - 20;
           break;
       case"right":
           x = x + 20;
           break;
       case"bottom":
           y = y + 20;
           break;
       case"top":
           y = y - 20;
           break
   }
   return {left: x, top: y}
};
Snake.prototype.move = function () {
   var obj = this.getNewHeadLoaction();
   if (obj.left < 0 || obj.left == 900 || obj.top < 0 || obj.top == 600) {
       alert("想不开死了");
       return true
   }
   var last = this.bodys.pop();
   last.className = "snake-head";
   var oldHead = this.bodys[0];
   oldHead.className = "snake-body";
   this.bodys.unshift(last);
   last.style.left = obj.left + "px";
   last.style.top = obj.top + "px";
   if (obj.left == this.food.x && obj.top == this.food.y) {
       this.insertNewHead();
       this.food.randomLoaction()
   }
   return false
};

function Game(m) {
   this.food = new Food(m);
   this.snake = new Snake(m, this.food)
}

Game.prototype.start = function () {
   this.food.randomLoaction();
   var snake = this.snake;
   var flag = window.setInterval(function () {
       var isDead = snake.move();
       console.log(isDead);
       if (isDead) {
           clearInterval(flag)
       }
   }, 100);
   document.onkeydown = function (e) {
       var code = e.keyCode;
       switch (code) {
           case 37:
               if (snake.direction != "right") {
                   snake.direction = "left"
               }
               break;
           case 38:
               snake.direction = "top";
               break;
           case 39:
               snake.direction = "right";
               break;
           case 40:
               snake.direction = "bottom";
               break
       }
   }
};

food.js

 (function (w) {
  // 形参w用来接收window对象,目的是为了缩短访问window的时间,提高程度性能。
  // 1. 定义一个食物的构造函数
  function Food(m) {
    // 食物的横向位置
    this.x = 0;
    // 食物的纵向位置
    this.y = 0;
    // 创建一个div元素
    this.div = document.createElement('div');
    // 设置div的类名
    this.div.className = 'food';
    // 地图属性
    this.map = m;
    // 把div放进地图中
    this.map.appendChild(this.div);

  }

  // 2. 定义一个随机食物的方法放入原型中
  Food.prototype.randomLoaction = function () {
    // this代表谁?看将来的调用者。 this→调用者。


    // 将来横向的最大索引
    var maxX = 900 / 20 - 1;
    // 将来纵向的最大索引
    var maxY = 600 / 20 - 1;

    // 随机出横向和纵向的位置索引
    //[0,maxX]
    var indexX = getIntNum(0, maxX);
    //[0,maxY]
    var indexY = getIntNum(0, maxY);
    // 计算位置,这里的x和y并不会直接影响div,而是保留下来为了将来和蛇头的位置对比。
    this.x = indexX * 20;
    this.y = indexY * 20;

    // 设置div的left和top值
    this.div.style.left = this.x + 'px';
    this.div.style.top = this.y + 'px';



  };

  // 获取n-m之间的随机数 [n,m]
  function getIntNum(min, max) {
    // (max-min + 1) + min
    var num = parseInt(Math.random() * (max - min + 1) + min);
    return num;
  }

  // 把Food放到window中,就可以暴露出去
  // window是对象
  w.Food = Food;

}(window));

game.js

(function (w) {
  // 游戏构造函数

  function Game(m) {

    // 游戏中的食物
    this.food = new Food(m);
    // 游戏中的蛇
    this.snake = new Snake(m, this.food);
  }

  // 开始方法
  Game.prototype.start = function () {
    //0. 随机一下食物
    this.food.randomLoaction();
    // this → game
    var snake = this.snake;
    // 1. 开启定时器,让蛇不断的移动
    var flag = window.setInterval(function () {
      // this代表window
      // 2. 调用蛇的move方法
      var isDead = snake.move();
      console.log(isDead);
      // 判断是否死了
      if (isDead) {
        clearInterval(flag);
      }
      
    }, 100);

    //2. 给文档注册键盘按下事件
    document.onkeydown = function (e) {
      // 获取键码值
      var code = e.keyCode;
      // 判断四种情况,更改蛇的方向,先判断蛇的移动方向
      switch (code) {
        case 37: // 左侧
          if (snake.direction != 'right') {
            snake.direction = 'left';
          }
          break;
        case 38: // 上侧
          snake.direction = 'top';
          break;
        case 39: // 右侧
          snake.direction = 'right';
          break;
        case 40: // 下侧
          snake.direction = 'bottom';
          break;
      }
    };

  };

  //通过window将Game暴露出去
  w.Game = Game;
}(window));

snake.js

(function (w) {
  // 构造函数
  function Snake(m, f) {
    // 蛇移动的方向 left  top right bottom
    this.direction = 'right';
    // 蛇的节数 蛇节中的第0个div是蛇头 后面其他的都是蛇身
    this.bodys = [];
    // 蛇的要追加的地图
    this.map = m;
    // 蛇要吃的食物
    this.food = f;
    // 生成蛇
    this.createBodys();
  }

  // 生成蛇
  Snake.prototype.createBodys = function () {
    // 增加三个新蛇头,初始化为3节
    for (var i = 0; i < 3; i++) {
      this.insertNewHead();
    }


  };

  // 增加蛇头
  Snake.prototype.insertNewHead = function () {
    // 创建一个div,表示新的蛇头
    var newHead = document.createElement('div');
    // 设置类名
    newHead.className = 'snake-head';
    // 计算新蛇头的位置
    var location = this.getNewHeadLoaction();
    // 把计算好的位置设置给新蛇头元素
    newHead.style.left = location.left + 'px';
    newHead.style.top = location.top + 'px';
    // 把新蛇头放入地图中
    this.map.appendChild(newHead);
    // 获取旧的蛇头,看是否存在,若存在,把旧的蛇头改为身体
    var oldHead = this.bodys[0];
    if (oldHead != undefined) {
      oldHead.className = 'snake-body';
    }

    // 把新蛇节放到蛇的bodys中
    this.bodys.unshift(newHead);
  };

  // 计算新蛇头的位置,返回两个数据
  Snake.prototype.getNewHeadLoaction = function () {
    // 定义两个变量,分别表示计算后新蛇头的位置
    var x = 0; y = 0;
    // 判断是否有蛇头
    var oldHead = this.bodys[0];
    // 若没有蛇头,将来返回 {left:0,top:0}
    if (oldHead == undefined) {
      return { left: x, top: y };
    }
    // 有蛇头,则计算。 获取原有蛇头的位置
    x = oldHead.offsetLeft;
    y = oldHead.offsetTop;
    // 根据蛇移动的方向计算
    switch (this.direction) {
      case 'left':
        x = x - 20;
        break;
      case 'right':
        x = x + 20;
        break;
      case 'bottom':
        y = y + 20;
        break;
      case 'top':
        y = y - 20;
        break;
    }

    return { left: x, top: y };


  };

  // 蛇移动方法
  Snake.prototype.move = function () {
    // 1. 计算并获取新蛇头的位置
    var obj = this.getNewHeadLoaction();
    // 1.1 判断蛇头的位置是否已经越过边界
    if (obj.left < 0 || obj.left == 900 || obj.top < 0 || obj.top == 600) {
      alert('想不开死了');
      return true;  // 这里的返回值,主要高速定时器,蛇是否死了
    }
    // 2. 从蛇的bodys中取出最后节 pop()
    var last = this.bodys.pop();
    // 3. 设置最后一节的类名为蛇头 snake-head
    last.className = 'snake-head';
    // 4. 获取旧的蛇头
    var oldHead = this.bodys[0];
    // 5. 把旧的蛇头改为身体       snake-body
    oldHead.className = 'snake-body';
    // 6. 把最后一节追加到数组的最前面
    this.bodys.unshift(last);
    // 7. 把新蛇头的位置赋值给最后一节的left和top样式
    last.style.left = obj.left + 'px';
    last.style.top = obj.top + 'px';


    // 8 判断蛇有没有吃到食物
    if (obj.left == this.food.x && obj.top == this.food.y) {
      // console.log('吃了')
      // 8.1 蛇要增加一节
      this.insertNewHead();
      // 8.2 食物要随机一下位置
      this.food.randomLoaction();
    }

    return false;
  }

  w.Snake = Snake;
}(window));

猜你喜欢

转载自blog.csdn.net/github_27314097/article/details/82988719