実戦——対象に向かって+原型を実現した食いしん坊蛇

62914 ワード

対象+プロトタイプに向かって食いしん坊を実現
前のあの食いしん坊蛇https://blog.csdn.net/F_Felix/article/details/89676816)対象向けにも使われていますが、ゲーム自体が同じ対象となるように、JavaScriptのプロトタイプを使っているのと同じように、この食いしん坊蛇を分析してみます.
考え方の分析
1、全部でいくつの相手がいますか?ここには4つのオブジェクトがあります.それぞれSnake、Food、Game、mapですが、簡単な点のためにmapオブジェクトを省略しました.前の編の2、各オブジェクトを直接使うなら、どのような属性と方法がありますか?
  • Foodオブジェクト:幅の高さ、色、位置の属性およびレンダリング方法(width、height、bgColor、x、yおよびrender)
  • Snakeオブジェクト:幅、方向、頭の色、体の色、体の属性及びレンダリング及び移動方法(width、height、direction、headColor、bodyColor、body、render、move)
  • Gameオブジェクト:地図、蛇、食べ物の属性と初期化、初期化ゲーム、スタートゲーム、一時停止ゲーム、リセットゲーム、終了ゲーム、操作蛇のオブジェクト(map、snake、food、init、start、pause、control、reet)
  • 3、どのように前の基礎の上で最適化を行いますか?
  • は、方法をプロトタイプに定義し、構造関数
  • に属性を定義する.
  • 沙箱を使ってコードをくるみ、大域汚染を避ける(説明:https://blog.csdn.net/F_Felix/article/details/90111118)
  • それから多くなく説明しました.コードの中にコメントがあります.直接コードをつけます.
    ページコード
    
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .map {
        width: 800px;
        height: 500px;
        background-color: #000;
        margin: 0 auto;
        position: relative;
      }
      p {
        text-align: center;
        line-height: 30px;
      }
      .btn {
        margin: 0 auto;
        text-align: center;
      }
    style>
    
    <body>
      <div class="btn">
        <button class="begin">    button>
        <button class="pause">    button>
        <button class="reset">    button>
      div>
      <p>
        <strong>    :strong>Enter-->      Space-->      Esc--->
             ←↑→↓     
      p>
      <p>   10      ,    50,    200p>
      <div class="map">div>
      <script src="food.js">script>
      <script src="snake.js">script>
      <script src="game.js">script>
      <script>
        var map = document.querySelector('.map')
        var btn1 = document.querySelector('.begin')
        var btn2 = document.querySelector('.pause')
        var btn3 = document.querySelector('.reset')
        var g = new Game({
          map: map
        })
        g.init()
    
        btn1.onclick = function() {
          g.start()
        }
        btn2.onclick = function() {
          g.pause()
        }
        btn3.onclick = function() {
          g.reset()
        }
        //   js        ,                
        document.onkeydown = function(e) {
          switch (e.keyCode) {
            case 13:
              btn1.focus()
              break
            case 32:
              btn2.focus()
              break
            case 27:
              btn3.focus()
              break
          }
        }
      script>
    body>
    
    Foodオブジェクト
    //   4----         
    ;(function(window) {
      /**
       *       
       * @param {object} options     
       *     :  、  、  、  
       *     :  
       */
      function Food(options) {
        options = options || {}
        this.width = options.width || 20
        this.height = options.height || 20
        this.bgColor = options.bgColor || 'cyan'
        this.x = 0
        this.y = 0
      }
    
      Food.prototype.render = function(target) {
        //   1,                ,          
        this.node && target.removeChild(this.node)
    
        //       ,        map  
        var div = document.createElement('div')
        this.node = div
        target.appendChild(div)
        div.style.width = this.width + 'px'
        div.style.height = this.height + 'px'
        div.style.backgroundColor = this.bgColor
        div.style.position = 'absolute'
        this.x = ((Math.random() * target.offsetWidth) / this.width) | 0
        this.y = ((Math.random() * target.offsetHeight) / this.height) | 0
        div.style.left = this.x * this.width + 'px'
        div.style.top = this.y * this.height + 'px'
        div.style.borderRadius = '50%'
      }
      window.Food = Food
    })(window)
    
    Snakeオブジェクト
    ;(function(window) {
      /**
       *      
       * @param {*} options       (  )
       *    :         ,  ,  ,     
       *    :  、  
       */
      function Snake(options) {
        options = options || {}
        this.width = options.width || 20
        this.height = options.height || 20
        this.direction = options.direction || 'right'
        this.headColor = options.headColor || 'skyblue'
        this.bodyColor = options.bodyColor || 'yellowgreen'
        this.body = [{ x: 2, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 0 }]
      }
      //      map 
      Snake.prototype.render = function(target) {
        //   2              
        var spans = document.querySelectorAll('span')
        for (var i = 0; i < spans.length; i++) {
          target.removeChild(spans[i])
        }
        for (var i = 0; i < this.body.length; i++) {
          var span = document.createElement('span')
          target.appendChild(span)
          span.style.width = this.width + 'px'
          span.style.height = this.height + 'px'
          span.style.backgroundColor = i === 0 ? this.headColor : this.bodyColor
          span.style.position = 'absolute'
          span.style.left = this.body[i].x * this.width + 'px'
          span.style.top = this.body[i].y * this.height + 'px'
          span.style.borderRadius = '50%'
        }
      }
      //     
      Snake.prototype.move = function(target, food) {
        /* 
                :
                        ,          
                                
                              
                                    
        */
        var head = {
          x: this.body[0].x,
          y: this.body[0].y
        }
        switch (this.direction) {
          case 'right':
            head.x++
            break
          case 'left':
            head.x--
            break
          case 'up':
            head.y--
            break
          case 'down':
            head.y++
            break
        }
        this.body.unshift(head)
        //               ,      
        if (head.x == food.x && head.y == food.y) {
          //      ,   food       --->   1
          food.render(target)
        } else {
          this.body.pop()
        }
        //   4         ,                
        if (
          head.x < 0 ||
          head.y < 0 ||
          head.x >= target.offsetWidth / this.width ||
          head.y >= target.offsetHeight / this.height
        ) {
          return
        }
        //   2         ,             ,     
        this.render(target)
      }
      window.Snake = Snake
    })(window)
    
    ゲームオブジェクト
    //   4 --         
    ;(function(window) {
      /**
       *     
       * @param {*} options       
       *     :  、 、  、     
       *   :     、    、    、    、    、     (      )
       */
      function Game(options) {
        options = options || {}
        this.map = options.map
        this.snake = options.snake || new Snake()
        this.food = options.food || new Food()
        this.duration = 200 //     
        this.limit = 50 //      50ms
        this.level = 10 //          
      }
    
      //   3          
      var dirFlag = true //      --->              ,      
      var gameFlag = true //       --->                     
    
      var tId //    id
      var these //      start          this,       ,           
      var prevLength = 3 //         3
    
      //      
      Game.prototype.init = function() {
        this.snake.render(this.map)
        this.food.render(this.map)
        //               start 
        this.control()
      }
    
      //     
      Game.prototype.start = function() {
        if (gameFlag) {
          gameFlag = false
          //      this      this       ,       
          // var that = this;
          // this.timeId = setInterval(function () {
          //     //   :   this    this     ,      window  
          //     that.snake.move(that.map, that.food);
          //     //     
          //     that.gameOver();
    
          //     //                 
          //     setTimeout(() => {
          //         dirFlag = true;
          //     }, 100);
          // }, this.duration);
          these = this
          // tId = setInterval('execute(these)', this.duration)
          tId = setInterval(() => {
            execute(these)
          }, this.duration)
        }
      }
    
      //     ,       
      function execute(these) {
        //   :   this    this     ,      window  
        these.snake.move(these.map, these.food)
        //     
        these.gameOver()
    
        clearInterval(tId)
    
        if (
          these.snake.body.length - prevLength >= these.level &&
          these.duration >= these.limit
        ) {
          prevLength = these.snake.body.length
          these.duration -= 10
          console.log(these.duration)
        }
        // var that = tt;
        //           ,          ,          
        if (!gameFlag) {
          tId = setInterval(() => {
            execute(these)
          }, these.duration)
        }
    
        //                 
        setTimeout(() => {
          dirFlag = true
        }, 100)
      }
      //     
      Game.prototype.gameOver = function() {
        var head = this.snake.body[0]
        // 1、     ---> 
        if (
          head.x < 0 ||
          head.y < 0 ||
          head.x >= this.map.offsetWidth / this.snake.width ||
          head.y >= this.map.offsetHeight / this.snake.height
        ) {
          alert('Game Over!')
          this.pause()
          gameFlag = true
        }
        // 2、     ---> 
        for (var i = 4; i < this.snake.body.length; i++) {
          if (head.x == this.snake.body[i].x && head.y == this.snake.body[i].y) {
            alert('Game Over!')
            this.pause()
            gameFlag = true
          }
        }
      }
    
      //     
      Game.prototype.pause = function() {
        // clearInterval(this.timeId);
        clearInterval(tId)
        gameFlag = true
        dirFlag = true
      }
    
      //             、  、  
      Game.prototype.control = function() {
        var that = this
        document.addEventListener('keydown', function(e) {
          if (dirFlag) {
            dirFlag = false
            switch (e.keyCode) {
              case 37:
                if (that.snake.direction != 'right') {
                  that.snake.direction = 'left'
                }
                break
              case 38:
                if (that.snake.direction != 'down') {
                  that.snake.direction = 'up'
                }
                break
              case 39:
                if (that.snake.direction != 'left') {
                  that.snake.direction = 'right'
                }
                break
              case 40:
                if (that.snake.direction != 'up') {
                  that.snake.direction = 'down'
                }
                break
              case 32:
                that.pause()
                break
              case 13:
                that.start()
                break
              case 27:
                that.reset()
                break
            }
          }
        })
      }
    
      //     
      Game.prototype.reset = function() {
        this.snake.body = [{ x: 2, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 0 }]
        this.snake.direction = 'right'
        this.init()
        // clearInterval(this.timeId);
        clearInterval(tId)
        gameFlag = true
        dirFlag = true
      }
    
      window.Game = Game
    })(window)
    
    ゲーム中の方法について簡単に説明してください.
    1、     these = this?(start   )
         :        ,this   window ,     this      Game  ,       this    these,              these     Game 。(      these = this   ,         )
                  ,  ,             '       '  bind  ,      this   Game   this
        tId = setInterval(function(){
            execute(this)
        }.bind(this),this.duration)
    2、            execute  ?
         :                            ,     function     this.duration      ,        ,              ,           ,                      
    3、        ?
         :       ,            ,                        ,                over,   :        ,           ,    (   )      ,                ,      。       ,         ,              ,          ,        ,          ,           。
    4、      ?
         :       ,          ,                    ,         。