国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Javascript編寫2048小游戲

2019-11-20 12:05:11
字體:
來源:轉載
供稿:網友

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

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

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

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

  效果圖如下:

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

  Data是構造函數, 會把數據構造出來, 數據會繼承原型上的一些方法;

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

  Data的結構如下:

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

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

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

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

  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";    }    //這個應該算是服務;  };

  下面是全部的代碼, 引用的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>    <% } %>      <!--生成數字塊元素--->    <% for(var j=0; j< data[i].length; j++ ) { %>      <!--如果數據模型里面的值為0,那么不顯示這個數據的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 構造函數初始化     * */    init : function() {      this.generateData();    },    /**     * @desc 生成了默認的數據地圖     * @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填充到數據里面     * @return void     * */    generationBlock : function() {      var data = this.getRandom();      var position = this.getPosition();      this.set( position.x, position.y, data)    },    /**     * @desc 獲取隨機數 2 或者是 4     * @return 2 || 4;     * */    getRandom : function() {      return Math.random()>0.5 ? 2 : 4;    },    /**     * @desc 獲取data里面數據內容為空的位置     * @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 把數據里第y排, 第x列的設置, 默認為0, 也可以傳值;     * @param x, y     * */    set : function(x,y ,arg) {      this.map[y][x] = arg || 0;    },    /**     * @desc 在二維數組的區間中水平方向是否全部為0     * @desc i明確了二維數組的位置, k為開始位置, j為結束為止     * */    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() {      /*      * 往左邊移動;      * 從上到下, 從左到右, 循環;      * 從0開始繼續循環到當前的元素 ,如果左側的是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是因為,當前的元素已經移動到了初始的位置,之間的循環我們根本不需要走了                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 = [];      // 循環要檢測的長度      for(var i=0; i<data[0].length; i++ ) {        // 循環要檢測的高度        for(var j=1; j<data.length; j++) {          if (data[j][i] != 0) {            //x是確定的, 循環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 = [];      // 循環要檢測的長度      for(var i=0; i<data[0].length; i++ ) {        // 循環要檢測的高度        for(var j=data.length - 1; j>=0 ; j--) {          if (data[j][i] != 0) {            //x是確定的, 循環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";    }    //這個應該算是服務;  };  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();    //隨機生成兩個節點;    data.generationBlock();    data.generationBlock();    //生成視圖    var view = new View({ data :data, el : document.getElementById("g") });    //繼承工具方法, 主要是動畫效果的繼承;    $.extend( true, view, util );    //顯示界面    view.renderHTML();  });</script></body></html>

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 衡东县| 筠连县| 黔江区| 灵丘县| 石河子市| 神农架林区| 温州市| 若羌县| 桂东县| 东台市| 武乡县| 金沙县| 玉溪市| 绿春县| 化州市| 太仆寺旗| 富源县| 广德县| 界首市| 民丰县| 望城县| 朝阳县| 宽甸| 静安区| 达拉特旗| 澜沧| 万全县| 浑源县| 津市市| 玉溪市| 梁平县| 浠水县| 隆昌县| 崇文区| 洪洞县| 西贡区| 郁南县| 神池县| 东丽区| 都江堰市| 东丰县|