欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript編寫2048小游戲

 更新時間:2015年07月07日 11:19:56   投稿:hebedich  
本文給大家介紹的是去年很火的一款小游戲--2048用javascript實現(xiàn)的思路以及代碼,有需要的小伙伴可以參考下。

  去年2048很火, 本來我也沒玩過, 同事說如果用JS寫2048 只要100多行代碼;

  今天試了一下, 邏輯也不復雜, 主要是數(shù)據(jù)構(gòu)造函數(shù)上的數(shù)據(jù)的各種操作, 然后通過重新渲染DOM實現(xiàn)界面的更新, 整體不復雜, JS,css,和HTML合起來就300多行;

  界面的生成使用了underscore.js的template方法, 使用了jQuery,主要是DOM的選擇和操作以及動畫效果,事件的綁定只做了PC端的兼容,只綁定了keydown事件;

  把代碼放到github-page上, 通過點擊這里查看 實例: 打開2048實例;

  效果圖如下:

  所有的代碼分為兩大塊,Data, View;

  Data是構(gòu)造函數(shù), 會把數(shù)據(jù)構(gòu)造出來, 數(shù)據(jù)會繼承原型上的一些方法;

  View是根據(jù)Data的實例生成視圖,并綁定事件等, 我直接把事件認為是controller了,和View放在了一起, 沒必要分開;

  Data的結(jié)構(gòu)如下:

    /**
     * @desc 構(gòu)造函數(shù)初始化
     * */
    init : function
    /**
     * @desc 生成了默認的數(shù)據(jù)地圖
     * @param void
     * */
    generateData : function
    /**
     * @desc 隨機一個block填充到數(shù)據(jù)里面
     * @return void
     * */
    generationBlock : function
    /**
     * @desc 獲取隨機數(shù) 2 或者是 4
     * @return 2 || 4;
     * */
    getRandom : function
    /**
     * @desc 獲取data里面數(shù)據(jù)內(nèi)容為空的位置
     * @return {x:number, y:number}
     * */
    getPosition : function
    /**
     * @desc 把數(shù)據(jù)里第y排, 第x列的設(shè)置, 默認為0, 也可以傳值;
     * @param x, y
     * */
    set : function
    /**
     * @desc 在二維數(shù)組的區(qū)間中水平方向是否全部為0
     * @desc i明確了二維數(shù)組的位置, k為開始位置, j為結(jié)束為止
     * */
    no_block_horizontal : function
    no_block_vertica : function
    /**
     * @desc 往數(shù)據(jù)往左邊移動,這個很重要
     * */
    moveLeft : function
    moveRight : function
    moveUp : function
    moveDown : function

  有了數(shù)據(jù)模型,那么視圖就簡單了,主要是用底線庫underscore的template方法配合數(shù)據(jù)生成html字符串,然后對界面進行重繪:

View的原型方法:
        renderHTML : function //生成html字符串,然后放到界面中
        init : function //構(gòu)造函數(shù)初始化方法
        bindEvents : function //給str綁定事件, 認為是控制器即可
 

  因為原始的2048有方塊的移動效果, 我們獨立起來了一個服務(wù)(工具方法,這個工具方法會被View繼承), 主要是負責界面中的方塊的移動, getPost是給底線庫用的, 在模板生成的過程中需要根據(jù)節(jié)點的位置動態(tài)生成橫豎坐標,然后定位:

  var util = {
    animateShowBlock : function() {
      setTimeout(function() {
        this.renderHTML();
      }.bind(this),200);
    },
    animateMoveBlock : function(prop) {
      $("#num"+prop.form.y+""+prop.form.x).animate({top:40*prop.to.y,left:40*prop.to.x},200);
    },
    //底線庫的模板中引用了這個方法;
    getPost : function(num) {
      return num*40 + "px";
    }
    //這個應(yīng)該算是服務(wù);
  };

  下面是全部的代碼, 引用的JS使用了CDN,可以直接打開看看:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
<script src="http://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
<script src="http://cdn.bootcss.com/jquery/2.1.4/jquery.js"></script>
<style>
  #g{
    position: relative;
  }

  .block,.num-block{
    position: absolute;
    width: 40px;
    height: 40px;
    line-height: 40px;
    text-align: center;
    border-radius: 4px;
  }
  .block{
    border:1px solid #eee;
    box-sizing: border-box;
  }
  .num-block{
    color:#27AE60;
    font-weight: bold;
  }
</style>
  <div class="container">
    <div class="row">
      <div id="g">
      </div>
    </div>
  </div>

<script id="tpl" type="text/template">
  <% for(var i=0; i<data.length; i++) {%>
      <!--生成背景塊元素--->
    <% for(var j=0; j< data[i].length; j++ ) { %>
      <div id="<%=i%><%=j%>" class="block" style="left:<%=util.getPost(j)%>;top:<%=util.getPost(i)%>" data-x="<%=j%>" data-y="<%=i%>" data-info='{"x":<%=[j]%>,"y":<%=[i]%>}'>
      </div>
    <% } %>
      <!--生成數(shù)字塊元素--->
    <% for(var j=0; j< data[i].length; j++ ) { %>
      <!--如果數(shù)據(jù)模型里面的值為0,那么不顯示這個數(shù)據(jù)的div--->
      <% if ( 0!==data[i][j] ) {%>
        <div id="num<%=i%><%=j%>" class="num-block" style="left:<%=util.getPost(j)%>;top:<%=util.getPost(i)%>" >
          <%=data[i][j]%>
        </div>
      <% } %>
    <% } %>
  <% } %>
</script>
<script>
  var Data = function() {
    this.init();
  };
  $.extend(Data.prototype, {
    /**
     * @desc 構(gòu)造函數(shù)初始化
     * */
    init : function() {
      this.generateData();
    },
    /**
     * @desc 生成了默認的數(shù)據(jù)地圖
     * @param void
     * */
    generateData : function() {
      var data = [];
      for(var i=0; i<4; i++) {
        data[i] = data[i] || [];
        for(var j=0; j<4; j++) {
          data[i][j] = 0;
        };
      };
      this.map = data;
    },
    /**
     * @desc 隨機一個block填充到數(shù)據(jù)里面
     * @return void
     * */
    generationBlock : function() {
      var data = this.getRandom();
      var position = this.getPosition();
      this.set( position.x, position.y, data)
    },
    /**
     * @desc 獲取隨機數(shù) 2 或者是 4
     * @return 2 || 4;
     * */
    getRandom : function() {
      return Math.random()>0.5 ? 2 : 4;
    },
    /**
     * @desc 獲取data里面數(shù)據(jù)內(nèi)容為空的位置
     * @return {x:number, y:number}
     * */
    getPosition : function() {
      var data = this.map;
      var arr = [];
      for(var i=0; i<data.length; i++ ) {
        for(var j=0; j< data[i].length; j++ ) {
          if( data[i][j] === 0) {
            arr.push({x:j, y:i});
          };
        };
      };
      return arr[ Math.floor( Math.random()*arr.length ) ];
    },
    /**
     * @desc 把數(shù)據(jù)里第y排, 第x列的設(shè)置, 默認為0, 也可以傳值;
     * @param x, y
     * */
    set : function(x,y ,arg) {
      this.map[y][x] = arg || 0;
    },
    /**
     * @desc 在二維數(shù)組的區(qū)間中水平方向是否全部為0
     * @desc i明確了二維數(shù)組的位置, k為開始位置, j為結(jié)束為止
     * */
    no_block_horizontal: function(i, k, j) {
      k++;
      for( ;k<j; k++) {
        if(this.map[i][k] !== 0)
        return false;
      };
      return true;
    },
    //和上面一個方法一樣,檢測的方向是豎排;
    no_block_vertical : function(i, k, j) {
      var data = this.map;
      k++;
      for(; k<j; k++) {
        if(data[k][i] !== 0) {
          return false;
        };
      };
      return true;
    },
    /**
     * @desc 往左邊移動
     * */
    moveLeft : function() {
      /*
      * 往左邊移動;
      * 從上到下, 從左到右, 循環(huán);
      * 從0開始繼續(xù)循環(huán)到當前的元素 ,如果左側(cè)的是0,而且之間的空格全部為0 , 那么往這邊移,
      * 如果左邊的和當前的值一樣, 而且之間的空格值全部為0, 就把當前的值和最左邊的值相加,賦值給最左邊的值;
      * */
      var data = this.map;
      var result = [];
      for(var i=0; i<data.length; i++ ) {
        for(var j=1; j<data[i].length; j++) {
          if (data[i][j] != 0) {
            for (var k = 0; k < j; k++) {
              //當前的是data[i][j], 如果最左邊的是0, 而且之間的全部是0
              if (data[i][k] === 0 && this.no_block_horizontal(i, k, j)) {
                result.push( {form : {y:i,x:j}, to :{y:i,x:k}} );
                data[i][k] = data[i][j];
                data[i][j] = 0;
                //加了continue是因為,當前的元素已經(jīng)移動到了初始的位置,之間的循環(huán)我們根本不需要走了
                break;
              }else if(data[i][j]!==0 && data[i][j] === data[i][k] && this.no_block_horizontal(i, k, j)){
                result.push( {form : {y:i,x:j}, to :{y:i,x:k}} );
                data[i][k] += data[i][j];
                data[i][j] = 0;
                break;
              };
            };
          };
        };
      };
      return result;
    },
    moveRight : function() {
      var result = [];
      var data = this.map;
      for(var i=0; i<data.length; i++ ) {
        for(var j=data[i].length-2; j>=0; j--) {
          if (data[i][j] != 0) {
            for (var k = data[i].length-1; k>j; k--) {
              //當前的是data[i][j], 如果最左邊的是0, 而且之間的全部是0
              if (data[i][k] === 0 && this.no_block_horizontal(i, k, j)) {
                result.push( {form : {y:i,x:j}, to :{y:i,x:k}} );
                data[i][k] = data[i][j];
                data[i][j] = 0;
                break;
              }else if(data[i][k]!==0 && data[i][j] === data[i][k] && this.no_block_horizontal(i, j, k)){
                result.push( {form : {y:i,x:j}, to :{y:i,x:k}} );
                data[i][k] += data[i][j];
                data[i][j] = 0;
                break;
              };
            };
          };
        };
      };
      return result;
    },
    moveUp : function() {
      var data = this.map;
      var result = [];
      // 循環(huán)要檢測的長度
      for(var i=0; i<data[0].length; i++ ) {
        // 循環(huán)要檢測的高度
        for(var j=1; j<data.length; j++) {
          if (data[j][i] != 0) {
            //x是確定的, 循環(huán)y方向;
            for (var k = 0; k<j ; k++) {
              //當前的是data[j][i], 如果最上面的是0, 而且之間的全部是0
              if (data[k][i] === 0 && this.no_block_vertical(i, k, j)) {
                result.push( {form : {y:j,x:i}, to :{y:k,x:i}} );
                data[k][i] = data[j][i];
                data[j][i] = 0;
                break;
              }else if(data[j][i]!==0 && data[k][i] === data[j][i] && this.no_block_vertical(i, k, j)){
                result.push( {form : {y:j,x:i}, to :{y:k,x:i}} );
                data[k][i] += data[j][i];
                data[j][i] = 0;
                break;
              };
            };
          };
        };
      };
      return result;
    },
    moveDown : function() {
      var data = this.map;
      var result = [];
      // 循環(huán)要檢測的長度
      for(var i=0; i<data[0].length; i++ ) {
        // 循環(huán)要檢測的高度
        for(var j=data.length - 1; j>=0 ; j--) {
          if (data[j][i] != 0) {
            //x是確定的, 循環(huán)y方向;
            for (var k = data.length-1; k>j ; k--) {
              if (data[k][i] === 0 && this.no_block_vertical(i, k, j)) {
                result.push( {form : {y:j,x:i}, to :{y:k,x:i}} );
                data[k][i] = data[j][i];
                data[j][i] = 0;
                break;
              }else if(data[k][i]!==0 && data[k][i] === data[j][i] && this.no_block_vertical(i, j, k)){
                result.push( {form : {y:j,x:i}, to :{y:k,x:i}} );
                data[k][i] += data[j][i];
                data[j][i] = 0;
                break;
              };
            };
          };
        };
      };
      return result;
    }
   });
  var util = {
    animateShowBlock : function() {
      setTimeout(function() {
        this.renderHTML();
      }.bind(this),200);
    },
    animateMoveBlock : function(prop) {
      $("#num"+prop.form.y+""+prop.form.x).animate({top:40*prop.to.y,left:40*prop.to.x},200);
    },
    //底線庫的模板中引用了這個方法;
    getPost : function(num) {
      return num*40 + "px";
    }
    //這個應(yīng)該算是服務(wù);
  };
  var View = function(data) {
    this.data = data.data;
    this.el = data.el;
    this.renderHTML();
    this.init();
  };
  $.extend(View.prototype, {
    renderHTML : function() {
      var str = _.template( document.getElementById("tpl").innerHTML )( {data : this.data.map} );
      this.el.innerHTML = str;
    },
    init : function() {
      this.bindEvents();
    },
    bindEvents : function() {
      $(document).keydown(function(ev){
        var animationArray = [];
        switch(ev.keyCode) {
          case 37:
            animationArray = this.data.moveLeft();
            break;
          case 38 :
            animationArray = this.data.moveUp();
            break;
          case 39 :
            animationArray = this.data.moveRight();
            break;
          case 40 :
            animationArray = this.data.moveDown();
            break;
        };
        if( animationArray ) {
          for(var i=0; i<animationArray.length; i++ ) {
            var prop = animationArray[i];
            this.animateMoveBlock(prop);
          };
        };
        this.data.generationBlock();
        this.animateShowBlock();
      }.bind(this));
    }
  });

  $(function() {
    var data = new Data();
    //隨機生成兩個節(jié)點;
    data.generationBlock();
    data.generationBlock();
    //生成視圖
    var view = new View({ data :data, el : document.getElementById("g") });
    //繼承工具方法, 主要是動畫效果的繼承;
    $.extend( true, view, util );
    //顯示界面
    view.renderHTML();
  });
</script>
</body>
</html>

以上所述就是本文的全部內(nèi)容了,希望大家能夠喜歡。

相關(guān)文章

  • TypeScript里string和String的區(qū)別

    TypeScript里string和String的區(qū)別

    這篇文章主要介紹了TypeScript里string和String的區(qū)別,真的不止是大小寫的區(qū)別,string表示原生類型,而String表示對象,下文更多詳細內(nèi)容需要的小伙伴可以參考一下
    2022-03-03
  • JS/jQuery實現(xiàn)超簡單的Table表格添加,刪除行功能示例

    JS/jQuery實現(xiàn)超簡單的Table表格添加,刪除行功能示例

    這篇文章主要介紹了JS/jQuery實現(xiàn)超簡單的Table表格添加,刪除行功能,結(jié)合實例形式詳細分析了JS與jQuery針對Table表格添加,刪除行功能的相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07
  • js評分組件使用詳解

    js評分組件使用詳解

    這篇文章主要為大家介紹了js評分組件的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • 微信小程序自動化部署的全過程

    微信小程序自動化部署的全過程

    由于微信小程序需要在微信小程序助手上發(fā)布,比較麻煩,可以配置CI 自動化的發(fā)布,下面這篇文章主要給大家介紹了關(guān)于微信小程序自動化部署的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • 詳解?Map?和?WeakMap?區(qū)別以及使用場景

    詳解?Map?和?WeakMap?區(qū)別以及使用場景

    這篇文章主要介紹了詳解?Map?和?WeakMap?區(qū)別以及使用場景,Map本質(zhì)上是一個鍵值對的集合,WeakMap?只能將對象作為鍵名,下面來一起倆姐更多詳細內(nèi)容吧,希望這一篇文章能讓你對?Map?有更好的理解,或者能夠幫你理解?Map?和?WeakMap
    2022-01-01
  • 淺談webpack 構(gòu)建性能優(yōu)化策略小結(jié)

    淺談webpack 構(gòu)建性能優(yōu)化策略小結(jié)

    webpack以其豐富的功能和靈活的配置而深受業(yè)內(nèi)吹捧,逐步取代了grunt和gulp成為大多數(shù)前端工程實踐中的首選,這篇文章主要介紹了淺談webpack 構(gòu)建性能優(yōu)化策略小結(jié),感興趣的小伙伴們可以參考一下
    2018-06-06
  • js Calender控件使用詳解

    js Calender控件使用詳解

    這篇文章主要介紹了js Calender控件使用詳解,需要的朋友可以參考下
    2015-01-01
  • 基于Bootstrap實現(xiàn)tab標簽切換效果

    基于Bootstrap實現(xiàn)tab標簽切換效果

    這篇文章主要為大家詳細介紹了基于Bootstrap實現(xiàn)tab標簽切換效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • js漢字排序問題 支持中英文混排,兼容各瀏覽器,包括CHROME

    js漢字排序問題 支持中英文混排,兼容各瀏覽器,包括CHROME

    這套排序機制同時兼容了IE和ff 可以實現(xiàn)所有瀏覽器下排序的統(tǒng)一哦
    2011-12-12
  • 網(wǎng)頁圖片延時加載的js代碼

    網(wǎng)頁圖片延時加載的js代碼

    大家如果使用firebug去查看的話就會發(fā)現(xiàn),當你滾動到相應(yīng)的行時,當前行的圖片才即時加載的,這樣子的話頁面在打開只加可視區(qū)域的圖片,而其它隱藏的圖片則不加載,一定程序上加快了頁面加載的速度,對于比較長的頁面來說,這個方案是比較好的。
    2010-04-04

最新評論