美文网首页
JavaScript手写贪吃蛇小游戏

JavaScript手写贪吃蛇小游戏

作者: 又菜又爱分享的小肖 | 来源:发表于2021-07-24 10:51 被阅读0次

大家小时候都玩过诺基亚里面的贪吃蛇吧,今天也来自己写个贪吃蛇小游戏。

  1. 首先呢。需要创建自己的地图,一个宽为800px,高为600px,定位在浏览器的左上角。
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>贪吃蛇</title>
  <style>
    #map {
      width: 800px;
      height: 600px;
      background-color: #ccc;
      position: relative;
      top: 0px;
      left: 0px;
    }
  </style>
</head>
<body>
<div id="map"></div>
</body>
</html>
  1. 我们现在需要创建一个食物,我们发现贪吃蛇里面的每一个食物都有宽,高,背景色,位置(x,y)坐标轴,用编程中面向对象的思维,可以视为食物就是一个对象,那就需要一个创建食物对象的构造函数。
    // 如果Food函数未传值,那就默认为宽为20px,高为20px,背景色为绿色,(x,y)坐标都为0就是原点。
    function Food(width = 20, height = 20, bgc = 'green', x = 0, y = 0) {
        this.width = width;
        this.height = height;
        this.bgc = bgc;
        this.x = x;
        this.y = y;
    }
  1. 那如何把这个食物对象显示在地图上呢?这时候需要一个显示食物对象的一个函数。
    Food.prototype.render = function (map) {
        //给食物对象随机坐标x, y
        //offsetWidth = border + padding + height;
        //Math.random()方法返回一个大于等于0小于1的随机数
        //Math.floor()方法执行向下取整
        this.x = Math.floor(Math.random() * map.offsetWidth / this.width) * this.width;
        this.y = Math.floor(Math.random() * map.offsetHeight / this.height) * this.height;
        //创建一个div,让这个div拥有这个食物对象的所有信息 (把食物对象的xy宽高背景色都赋值给这个div)
        let box = document.createElement('div');
        box.style.position = "absolute";
        box.style.left = this.x + 'px';
        box.style.top = this.y + 'px';
        box.style.backgroundColor = this.bgc;
        box.style.width = this.width + 'px';
        box.style.height = this.height + 'px';
        //把这个div添加到map地图中
        map.appendChild(box);
    }

4.然后在这个构造函数暴露出去。

window.Food = Food;
  1. 导入到html文件中,实例化Food构造函数
let food = new Food();
food.render(map);

这个时候我们的随机食物就已经做出来了,接下来去写蛇这个对象

  1. 蛇有什么特点呢?蛇和食物一样是有宽,高,背景色,还会移动,移动的方向,(x,y)坐标轴,蛇也是一个对象
    function Snake(width = 20, height = 20, direction = 'right') {
        this.width = width;
        this.height = height;
        this.direction = direction;
        //这个body就是描述蛇的每一节的
        this.body = [
            { x: 3, y: 1, bgc: 'red' },
            { x: 2, y: 1, bgc: 'pink' },
            { x: 1, y: 1, bgc: 'green' }
        ]
    }

2.把创建出来的蛇显示在地图上

    Snake.prototype.render = function (map) {
        //遍历蛇一节一节的显示
        for (let i = 0; i < this.body.length; i++) {
            let item = this.body[i];
            let box = document.createElement('div');
            box.style.position = 'absolute';
            box.style.left = item.x * this.width + 'px';
            box.style.top = item.y * this.height + 'px';
            box.style.width = this.width + 'px';
            box.style.height = this.height + 'px';
            box.style.backgroundColor = item.bgc;
            //把box添加到map中
            map.appendChild(box);
        }
    }

3.让蛇动起来吃东西

    Snake.prototype.move = function (food, map) {
        //除了蛇头之外的蛇身边的坐标改变
        for (var i = this.body.length - 1; i > 0; i--) {
            this.body[i].x = this.body[i - 1].x;
            this.body[i].y = this.body[i - 1].y;
        }
        //蛇头的坐标改变
        switch (this.direction) {
            case 'right':
                this.body[0].x++;
                break;
            case 'left':
                this.body[0].x--;
                break;
            case 'top':
                this.body[0].y--;
                break;
            case 'bottom':
                this.body[0].y++;
                break;
        }
        //判断蛇是否吃到了食物.
        //如果蛇头的坐标与食物的坐标重叠,那就说明蛇已经吃到了食物
        var snakeHeadX = this.body[0].x * this.width; //蛇头的x坐标.
        var snakeHeadY = this.body[0].y * this.height; //蛇头的y坐标
        var foodX = food.x;//食物的x坐标
        var foodY = food.y;//食物的y坐标.
        //先拿到蛇尾巴(方便取他的xy)
        var lastSnakeUnit = this.body[this.body.length - 1];
        //判断
        if (snakeHeadX == foodX && snakeHeadY == foodY) {
            //吃到了食物就要长身体.
            this.body.push({
                x: lastSnakeUnit.x,
                y: lastSnakeUnit.y,
                bgColor: getRandomColor()
            });
            //吃了食物要产生一个新的食物.
            food.render(map);
        }
    }

4.蛇每次吃到一个食物,那么蛇就会加一个box,这个box是随机颜色,我们需要写一个随机颜色的函数

    //随机生成16进制的颜色函数
    function getRandomColor() {
        let arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; //下标0-15
        let str = '#';
        //循环产生 6个 0-15的数.
        for (let i = 0; i < 6; i++) {
            let num = Math.floor(Math.random() * 16);
            //根据这个随机数,在arr数组中去取值.
            str += num;
        }
        return str;
    }

5.把这个蛇的构造函数暴露出去

window.Snake = Snake;
  1. 这个时候食物和蛇都有在地图上显示了,但是蛇还不能动,现在我们需要写一个让蛇不停的动起来的方法,本质就是用计时器不停的调用蛇的move和render方法。
    function snakeAutoMove() {
        var timerId = setInterval(function () {
            //判断蛇移动后有没有出界.
            //思路:蛇头的坐标小于0,或者大于宽高就出界.
            var snakeHeadX = this.snake.body[0].x * this.snake.width;//蛇头x坐标
            var snakeHeadY = this.snake.body[0].y * this.snake.height;//蛇头y坐标
            if (snakeHeadX < 0 || snakeHeadY < 0 || snakeHeadX >= this.map.offsetWidth || snakeHeadY >= this.map.offsetHeight) {
                alert('Game Over!');
                clearInterval(timerId);
                return;//判断蛇出界了,那就提前结束这个方法,就不要让他往下执行这个渲染.
            }
            this.snake.render(this.map);
        }.bind(that), 400);
    }
  1. 现在蛇能动了,现在需要控制蛇的运动方向,让蛇根据键盘按键来移动。
    function bindKey() {
        document.onkeydown = function (e) {
            e = e || window.event;
            //console.log(e.keyCode);//左37  上38 右39  下40
            switch (e.keyCode) {
                case 37:
                    if (this.snake.direction != 'right') {
                        this.snake.direction = 'left';
                    }
                    break;
                case 38:
                    if (this.snake.direction != 'bottom') {
                        this.snake.direction = 'top';
                    }
                    break;
                case 39:
                    if (this.snake.direction != 'left') {
                        this.snake.direction = 'right';
                    }
                    break;
                case 40:
                    if (this.snake.direction != 'top') {
                        this.snake.direction = 'bottom';
                    }
                    break;
            }
        }.bind(that);
    }

完整代码

index.html

<!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>贪吃蛇</title>
</head>
<script src="index.js"></script>
<body>
    <div id="map"></div>
</body>

</html>
<style>
    #map {
        position: relative;
        left: 0;
        top: 0;
        width: 800px;
        height: 600px;
        background-color: #ccc;
    }
</style>
<script>
//获取地图对象
let map = document.querySelector("#map");
  //实例化一个游戏控制器对象.
  var game1 = new Game(map);
  //调用游戏控制器的start方法让游戏开始.
  game1.start();
</script>

index.js

;(function (window) {
  //声明一个数组,用来保存食物
  var list = [];
  //1.经过分析,发现食物有宽/高/背景色/定位的xy坐标,所以食物是一个对象,那就有一个创建食物对象的构造函数.
  function Food(width,height,bgColor,x,y){
    this.width = width || 20;
    this.height = height || 20;
    this.bgColor = bgColor || "green";
    this.x = x || 0;
    this.y = y || 0;
  }

  Food.prototype.render = function (map) {
    //渲染新食物之前删除老食物div.
    remove(map);

    //2.1 给食物对象随机产生xy坐标
    this.x = Math.floor(Math.random()*map.offsetWidth/this.width) * this.width;
    this.y = Math.floor(Math.random()*map.offsetHeight/this.height)*this.height;
    //2.2 创建一个div,让这个div拥有这个食物对象的所有显示信息.(把食物对象的xy宽高背景色都赋值给div的样式)
    var div1 = document.createElement('div');
    div1.style.position = 'absolute';
    div1.style.left = this.x + "px";
    div1.style.top = this.y + 'px';
    div1.style.width = this.width + "px";
    div1.style.height = this.height + 'px';
    div1.style.backgroundColor = this.bgColor;
    //2.3 把这个div添加到map地图中.
    map.appendChild(div1);

    //2.4 把渲染食物的这个div用list数组存起来
    list.push(div1);
  }

  //删除老食物div的方法.
  function remove(map){
    for(var i = 0 ; i < list.length; i++){
      map.removeChild(list[i]);
    }
    list = []; //清空list
  }



  //3.把Food这个构造函数给暴露出去.
  window.Food = Food;

}(window));


//----------------------------------------------------------------------------------
;(function (window) {
  //随机产生一个十六进制的颜色的函数.
  function getColorForRandom(){
    var arr = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];  //下标0-15
    var str = "#";
    //循环产生 6个 0-15的数.
    for(var i = 0 ; i < 6; i++){
      var num = Math.floor(Math.random()*16);
      //根据这个随机数,在arr数组中去取值.
      str += arr[num];
    }
    return str;   //"#98de00"
  }




  //写蛇
  //声明一个数组list用来保存蛇.
  var list = [];

  //1.分析蛇也是有宽/高/背景色/移动的方向/定位xy坐标,蛇也是对象.
  function Snake(width,height,direction){
    this.width = width || 20;
    this.height = height || 20;
    this.direction = direction || 'right';
    //这个body就是描述蛇的每一节的.
    this.body = [
      {x:3,y:1,bgColor:'red'},
      {x:2,y:1,bgColor:'green'},
      {x:1,y:1,bgColor:'pink'}
    ];
  }


  //2.把创建出来的蛇对象显示在map地图上.
  Snake.prototype.render = function (map) {
    //渲染新蛇的时候删除老蛇(调用remove方法)
    remove(map);

    //2.1 遍历蛇一节一节的显示.
    for(var i = 0 ; i < this.body.length; i++){
      //2.2 创建div
      var div1 = document.createElement('div');
      //2.3 让这个div拥有这个蛇节的每一个显示信息
      div1.style.position = 'absolute';
      div1.style.top = this.body[i].y * this.height + 'px';
      div1.style.left = this.body[i].x * this.width + 'px';
      div1.style.width = this.width + 'px';
      div1.style.height = this.height + 'px';
      div1.style.backgroundColor = this.body[i].bgColor;
      //2.4 把div1添加到map中.
      map.appendChild(div1);

      //把渲染蛇用的div存进list数组中.
      list.push(div1);
    }
  }


  //4.删除老蛇的方法.
  function remove(map){
    //从map中移除老蛇div.
    for(var i = 0 ; i < list.length; i++){
      map.removeChild(list[i]);
    }
    //list数组清空.
    list.length = 0; // list = [];
  }


  //3.让蛇移动的方法写在蛇的原型中.
  Snake.prototype.move = function (food,map) {
    //除了蛇头之外的蛇身体的坐标改变
    for(var i = this.body.length-1; i>0 ;i--){
      this.body[i].x = this.body[i-1].x;
      this.body[i].y = this.body[i-1].y;
    }

    //蛇头的坐标改变
    switch (this.direction){
      case 'right':
        this.body[0].x++;
        break;
      case 'left':
        this.body[0].x--;
        break;
      case 'top':
        this.body[0].y--;
        break;
      case 'bottom':
        this.body[0].y++;
        break;
    }

    //判断蛇是否吃到了食物.
    //思路:蛇头的坐标和食物的坐标重合.
    var snakeHeadX = this.body[0].x * this.width; //蛇头的x坐标.
    var snakeHeadY = this.body[0].y * this.height; //蛇头的y坐标
    var foodX = food.x;//食物的x坐标
    var foodY = food.y;//食物的y坐标.
    //先拿到蛇尾巴(方便取他的xy)
    var lastSnakeUnit = this.body[this.body.length-1];
    //判断
    if(snakeHeadX == foodX && snakeHeadY == foodY){
      //吃到了食物就要长身体.
      this.body.push({
        x:lastSnakeUnit.x,
        y:lastSnakeUnit.y,
        bgColor:getColorForRandom()
      });
      //吃了食物要产生一个新的食物.
      food.render(map);
    }


  }



  //3.把Snake这个构造函数给暴露出去
  window.Snake = Snake;

}(window));


//------------------------------------------------------------------------
;(function (window) {
  //声明一个变量that,一开始赋值null
  var that = null;

  //1.创建游戏控制器对象的构造函数.
  function Game(map){
    //游戏控制器对象,里面有食物对象,食物对象是调用食物的构造函数创建出来的.
    this.food = new Food();
    //游戏控制器对象,里面有蛇对象,蛇对象是调用蛇的构造函数创建出来的.
    this.snake = new Snake();
    //游戏控制对象,里面有地图,地图是传进来的.
    this.map = map;

    //给that赋值.
    that = this;
  }

  //2.游戏开始的方法.
  Game.prototype.start = function () {
    //2.1 显示食物对象.
    this.food.render(this.map);
    //2.2 显示蛇对象
    this.snake.render(this.map);

    //2.3 让蛇动一下,调用蛇对象的move方法改坐标,调用蛇的render方法重新渲染.
    //this.snake.move();
    //this.snake.render(this.map);
    snakeAutoMove();

    //2.4 调用绑定按键方法.
    bindKey();
  }


  //3.写一个方法让蛇不停的动起来.本质就是用一个计时器不停的调用蛇的move和render方法.
  function snakeAutoMove(){
    var timerId = setInterval(function () {
      //需求:把此时这个this变成游戏控制器对象
      this.snake.move(this.food,this.map);

      //判断蛇移动后有没有出界.
      //思路:蛇头的坐标小于0,或者大于宽高就出界.
      var snakeHeadX = this.snake.body[0].x *this.snake.width;//蛇头x坐标
      var snakeHeadY = this.snake.body[0].y *this.snake.height;//蛇头y坐标
      if(snakeHeadX < 0 || snakeHeadY < 0 || snakeHeadX >= this.map.offsetWidth || snakeHeadY >= this.map.offsetHeight){
        alert('Game Over!');
        clearInterval(timerId);
        return;//判断蛇出界了,那就提前结束这个方法,就不要让他往下执行这个渲染.
      }

      this.snake.render(this.map);


    }.bind(that),400);
  }

  //4.绑定键盘按键方法,让蛇根据键盘按键来移动.
  function bindKey(){
    document.onkeydown = function (e) {
      e = e || window.event;
      //console.log(e.keyCode);//左37  上38 右39  下40
      switch(e.keyCode){
        case 37:
          if(this.snake.direction != 'right'){
            this.snake.direction = 'left';
          }
          break;
        case 38:
          if(this.snake.direction != 'bottom'){
            this.snake.direction = 'top';
          }
          break;
        case 39:
          if(this.snake.direction != 'left'){
            this.snake.direction = 'right';
          }
          break;
        case 40:
          if(this.snake.direction != 'top'){
            this.snake.direction = 'bottom';
          }
          break;
      }
    }.bind(that);
  }


  //3.把Game构造函数给暴露出去.
  window.Game = Game;

}(window));

相关文章

  • JavaScript手写贪吃蛇小游戏

    大家小时候都玩过诺基亚里面的贪吃蛇吧,今天也来自己写个贪吃蛇小游戏。 首先呢。需要创建自己的地图,一个宽为800p...

  • JavaScript实现贪吃蛇游戏

    今天使用JavaScript简单快速的实现一个贪吃蛇小游戏。首先分析一下如何实现,首先需要一个确定大小的区域,让“...

  • 小游戏之贪吃蛇

    贪吃蛇是我接触 JavaScript 这门语言写的第一个小游戏,因为其简单绝对是入门首先。前端这块最重要的就是 J...

  • 游戏 & Github Page

    1. snakewizard.github.io 贪吃蛇小游戏 2. mattbasile.github.io 龙...

  • 《极限贪吃蛇》

    贪吃蛇是一款非常有趣的小游戏。 益智有好玩,等你来体验

  • “贪吃蛇🐍”的一生

    前段时间,出于无聊,下载了“贪吃蛇”这个游戏,原本以为这样的小游戏没啥意思,没想到居然上头了。 “贪吃蛇”这个游戏...

  • 新贵 Rust — 贪吃蛇(1)

    今天开始用 Rust 写一个小游戏,大家可能都玩过—贪吃蛇,今天就写个贪吃蛇 snake。首先创建一个项目 sna...

  • 初级练手项目——用Python一步一步实现“智能”贪吃蛇!

    贪吃蛇作为一款经典的小游戏,想必大家一定并不陌生,今天我们就来用Python来设计与实现贪吃蛇游戏,回味一下童年的...

  • 小游戏 贪吃蛇

    内容 贪吃蛇游戏包含:1.游戏引擎,2.蛇,3.食物。 基本操作 蛇会自动走,键盘可控制方向(上下左右),碰到边界...

  • 自制简易贪吃蛇

    今天实现一款经典小游戏的实例,贪吃蛇想必大家都有接触过,当然今天实现的细节没有那么全面,只能算是简易版本的小游戏,...

网友评论

      本文标题:JavaScript手写贪吃蛇小游戏

      本文链接:https://www.haomeiwen.com/subject/dznymltx.html