2048小游戏分析

这两天写了个2048小游戏先看效果图:

 

现在分享一下它的逻辑:

首先要关注的就是它的页面结构:

容器中放置16个div用于,初始页背景的16个格子,注意class命名方式,这样命名可以用函数方便的进行布局,和其他功能操作。

  <div class="container">
            <div class="box--0-0"></div>
            <div class="box--0-1"></div>
            <div class="box--0-2"></div>
            <div class="box--0-3"></div>
            <div class="box--1-0"></div>
            <div class="box--1-1"></div>
            <div class="box--1-2"></div>
            <div class="box--1-3"></div>
            <div class="box--2-0"></div>
            <div class="box--2-1"></div>
            <div class="box--2-2"></div>
            <div class="box--2-3"></div>
            <div class="box--3-0"></div>
            <div class="box--3-1"></div>
            <div class="box--3-2"></div>
            <div class="box--3-3"></div>
        </div>

其次 数字所在的div并不是这16个div,而是在通过方向键移动的过程中另外动态生成的。这里我先用一个值为0的4 *4的二维数组来标记初始的16个div,然后移动过程中生成的数字根据坐标放到这个数组的相应位置。而动态div就是根据这个数组的值来生成的,值不为0,则生成div,值为0,相应位置不生成div

   //1:二维数组生成函数
       function getArr () {
           var arr =[];
           for( var i = 0; i < 4; i++){
                 arr[i]=[];
               for( var j = 0; j < 4; j++){
                 arr[i][j]=0
               }
           }
           return arr;
       }

  // 2: 创建16个容纳数字的方格函数
       function getBoxs(arr1) {
           //重新开始先移除包含数字的格子
         if(getChild(parents)>16){
            removeClassEle('news');
         }
        for( var i = 0; i < arr1.length; i++){
               for( var j = 0; j < arr1[0].length; j++){
                  if(arr1[i][j]===0){
                      continue;
                  }else{
                    var divs = document.createElement('div');
                    divs.setAttribute('id','news--'+i+'-'+j);
                    divs.setAttribute('class','news');
                    divs.style.left=20+j*120+'px';
                    divs.style.top=20+i*120+'px';
                    divs.innerText=arr1[i][j]
                    parents.appendChild(divs);
                  }
               }
           }
       }

第三点就是上下左右移动的逻辑

以向左移动为例:

向左移动=>首先判断能否向左移动(条件:向左移动列的左侧有空间或者移动列与它相邻的左侧列值相等 xx24||x224)=>移动完成改变之前定义的数组的值,然后再重新根据该数组动态布局,=>检测数组的剩余空间,然后在剩余的空间位置中随机添加一个值=》在根据数组动态布局

 //判断能否向左移动,可以向左移动的条件,1:存在数字的方格左侧不存在数字,2:存在数字但两者相同。x 1 xx |  1,1 xx | 1 x 1 x 
    function canLeft(arr){
        //我通过arr2来判断
     for(var i=0;i<arr.length;i++){
         //这里j等于1是因为第一列没必要判断,不用左移了
         for(var j=1;j<arr[0].length;j++){
                 for(var k=j-1; k>=0;k--){   //循环判断数字左侧的格子
                     if(arr[i][k]===0){
                         arr[i][k]=arr[i][k+1];
                         arr[i][k+1]=0;
                     }
                     else if(arr[i][k]===arr[i][k+1]){
                         arr[i][k]=arr[i][k]*2;
                         arr[i][k+1]=0;
                     }
                 }
             
         }
     }
     return arr
    }

//随机生成一个Box
function productRandomBox (arr){
    //首先盘算是否有空间
    var arr3 =[]; //放剩余空间

    var objs;
  for (var i=0;i<arr.length;i++){
      for (var j=0;j<arr[0].length;j++){
          if(arr[i][j]===0){
             arr3.push({"x":i,"y":j});
          }
      }
  }
      if(arr3.length>0){  //随机生成box的逻辑
         objs=Math.floor(Math.random()*(arr3.length));
            arr[arr3[objs].x][arr3[objs].y]=getNum()
            return arr
            
      }else{
          alert('GG思密达')
      }
 }

//左移事件,首先判断能否左移,然后随机生成数组,左移后,重新设定样式
    function goLeft (){
            getBoxs(canLeft(arr2));
           
            getBoxs( productRandomBox(arr2));
         
            getColor();
    }

主要逻辑就是这些,写完后发现还是很简单的,下面附上完整代码:

<!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>2048哈哈</title>
    <style>
    .parent{ text-align:center;}
    .restart{ cursor: pointer;  background: bisque; width: 100px; height: 30px; line-height: 30px; margin: auto; border-radius: 5px;}
    div[class|='box']{ width: 100px; height: 100px; background: #ccc0b3; position: absolute;}
    .news{ width: 100px; height: 100px; background-color: rgb(238, 228, 218); position: absolute; text-align:center; line-height: 100px;}
    .container { background:#bbada0; width: 500px; height: 500px; margin: 20px auto; position: relative;}
    </style>
</head>
<body>
    <div class="parent">
        <h1>唯美JS2048</h1>
        <p class="restart">new game</p>
        <span><strong>score:</strong><span class="score">0</span></span>
        <div class="container">
            <div class="box--0-0"></div>
            <div class="box--0-1"></div>
            <div class="box--0-2"></div>
            <div class="box--0-3"></div>
            <div class="box--1-0"></div>
            <div class="box--1-1"></div>
            <div class="box--1-2"></div>
            <div class="box--1-3"></div>
            <div class="box--2-0"></div>
            <div class="box--2-1"></div>
            <div class="box--2-2"></div>
            <div class="box--2-3"></div>
            <div class="box--3-0"></div>
            <div class="box--3-1"></div>
            <div class="box--3-2"></div>
            <div class="box--3-3"></div>
        </div>
    </div>
    <script>
    window.onload=function (){
    var games = document.getElementsByClassName('restart')[0];
        //设置16个方格样式函数
        function setStyle (box) {
            for (var i = 0; i < 4; i++){
                for (var j = 0; j < 4; j++){
                    var el = document.getElementsByClassName(box+'--'+i+'-'+j)[0];
                    el.style.left=20+j*120+'px';
                    el.style.top=20+i*120+'px';
                }
            }
        };
        setStyle('box');

       //接着创建另一组16个方格容纳数字---想想,当某位置数字不存在时,容纳数字的方格也不应该存在,所以应该设置一标记来判断数字是否存在,
       //例如:当我们初始化开始游戏时只有两个位置有方格,那就意味着只能创建两个方格
       //  我们用一个数组标记,初始值都为0;当出现数字,就把值赋给它,然后通过该数组判断。


        //1:二维数组生成函数
       function getArr () {
           var arr =[];
           for( var i = 0; i < 4; i++){
                 arr[i]=[];
               for( var j = 0; j < 4; j++){
                 arr[i][j]=0
               }
           }
           return arr;
       }
       //标记
       var arr1=getArr();
       var parents = document.getElementsByClassName('container')[0];
       // 2: 创建16个容纳数字的方格函数
       function getBoxs(arr1) {
           //重新开始先移除包含数字的格子
         if(getChild(parents)>16){
            removeClassEle('news');
         }
        for( var i = 0; i < arr1.length; i++){
               for( var j = 0; j < arr1[0].length; j++){
                  if(arr1[i][j]===0){
                      continue;
                  }else{
                    var divs = document.createElement('div');
                    divs.setAttribute('id','news--'+i+'-'+j);
                    divs.setAttribute('class','news');
                    divs.style.left=20+j*120+'px';
                    divs.style.top=20+i*120+'px';
                    divs.innerText=arr1[i][j]
                    parents.appendChild(divs);
                  }
               }
           }
       }
        //点击new game 随机位置生成数字赋予arr1
       function randoms(arr) {
         var random1 =  Math.floor(Math.random()*4);
         var random3 =  Math.floor(Math.random()*4);
         var random4 =  Math.floor(Math.random()*4);
         var random5 =  Math.floor(Math.random()*4);
         var random2 = Math.random()>0.5?2:4;
         arr[random1][random3]=random2;
         arr[random4][random5]=random2;
         return arr
       }
       var arr2=getArr()
       //new game点击事件
     games.addEventListener('click',function(){
        
          arr2 =randoms(arrval(arr1))
         //生成两个随机的包含数字的box
        getBoxs(arr2);
        
     })
   // 清除数组数据的函数
   function arrval(arr){
    for( var i = 0; i < arr.length; i++){
               for( var j = 0; j < arr[0].length; j++){
                 arr[i][j]=0
               }
           }
           return arr
    }
    //清除指定class的元素集合
    function removeClassEle(cls){
        var arr = document.getElementsByClassName(cls);
        var c=arr.length;
        var parents = arr[0].parentNode;
        for(var i = 0; i<c; i++){
            parents.removeChild(arr[0]);  //这里有些不明白,为什么移除子元素后arr长度会变呢?arr不是之前读取的吗
        }
    }
    //获取元素的所有子元素的长度
    function getChild(pa) {
        var arr=[];
        var child = pa.childNodes;
        for ( var i=0; i<child.length;i++){
            if(child[i].nodeType===1){
                arr.push(child[i])
            }
        }
        return arr.length;
    }
    //判断能否向左移动,可以向左移动的条件,1:存在数字的方格左侧不存在数字,2:存在数字但两者相同。x 1 xx |  1,1 xx | 1 x 1 x 
    function canLeft(arr){
        //我通过arr2来判断
     for(var i=0;i<arr.length;i++){
         //这里j等于1是因为第一列没必要判断,不用左移了
         for(var j=1;j<arr[0].length;j++){
                 for(var k=j-1; k>=0;k--){   //循环判断数字左侧的格子
                     if(arr[i][k]===0){
                         arr[i][k]=arr[i][k+1];
                         arr[i][k+1]=0;
                     }
                     else if(arr[i][k]===arr[i][k+1]){
                         arr[i][k]=arr[i][k]*2;
                         arr[i][k+1]=0;
                     }
                 }
             
         }
     }
     return arr
    }
    function canRight(arr){
       for(var i=0;i<arr.length;i++){
           for (var j=0;j<arr[0].length-1;j++){
                for(var k=j+1;k<arr[0].length;k++){
                   if(arr[i][k]===0){
                       arr[i][k]=arr[i][k-1];
                       arr[i][k-1]=0;
                   } else if(arr[i][k]===arr[i][k-1]){
                       arr[i][k]=arr[i][k]*2;
                       arr[i][k-1]=0;
                   }
                }
           }
       }
       return arr;
    }
    function canUp(arr){
        for(var i=1;i<arr.length;i++){
            for(var j=0;j<arr[0].length;j++){
                for(var k=i-1; k>=0;k--){
                    if(arr[k][j]===0){
                        arr[k][j]=arr[k+1][j];
                        arr[k+1][j]=0;
                    }else if(arr[k][j]===arr[k+1][j]){
                        arr[k][j]=arr[k][j]*2;
                        arr[k+1][j]=0;
                    }
                }
            }
        }
        return arr;
    }
    function canDown(arr){
        for(var i=0;i<arr.length-1;i++){
            for(var j=0;j<arr[0].length;j++){
                for(var k=i+1; k<arr.length;k++){
                    if(arr[k][j]===0){
                        arr[k][j]=arr[k-1][j];
                        arr[k-1][j]=0;
                    }else if(arr[k][j]===arr[k-1][j]){
                        arr[k][j]=arr[k][j]*2;
                        arr[k-1][j]=0;
                    }
                }
            }
        }
        return arr;
    }
    //左移事件,首先判断能否左移,然后随机生成数组,左移后,重新设定样式
    function goLeft (){
            getBoxs(canLeft(arr2));
           
            getBoxs( productRandomBox(arr2));
         
            getColor();
    }
    //右移事件
    function goRight() {
        getBoxs(canRight(arr2));
           getBoxs( productRandomBox(arr2));
           getColor();
    }
    //上移事件
    function goUp() {
        getBoxs(canUp(arr2));
           getBoxs( productRandomBox(arr2));
           getColor();
    }
    //下移事件
    function goDowm (){
        getBoxs(canDown(arr2));
           getBoxs( productRandomBox(arr2));
           getColor();
    }
    //键盘绑定事件
    document.addEventListener('keydown',function(e){
        var codes = window.event ? e.keyCode: e.which;
        switch (codes) {
            case 37 : 
            goLeft();
            break;
            case 38:
            goUp();
            break;
            case 39 :
            goRight();
            break;
            case 40:
            goDowm();
            break;
            default :
          
        }
    })
//随机生成一个Box
function productRandomBox (arr){
    //首先盘算是否有空间
    var arr3 =[]; //放剩余空间

    var objs;
  for (var i=0;i<arr.length;i++){
      for (var j=0;j<arr[0].length;j++){
          if(arr[i][j]===0){
             arr3.push({"x":i,"y":j});
          }
      }
  }
      if(arr3.length>0){  //随机生成box的逻辑
         objs=Math.floor(Math.random()*(arr3.length));
            arr[arr3[objs].x][arr3[objs].y]=getNum()
            return arr
            
      }else{
          alert('GG思密达')
      }
 }
 //随机生成一个2或者4的数字
 function getNum(){
     return Math.random()>0.5 ? 2 : 4;
 }
}
function setColor(number) {
    switch (number) {
    case 2:
        return "#eee4da";
        break;
    case 4:
        return "#eee4da";
        break;
    case 8:
        return "#f26179";
        break;
    case 16:
        return "#f59563";
        break;
    case 32:
        return "#f67c5f";
        break;
    case 64:
        return "#f65e36";
        break;
    case 128:
        return "#edcf72";
        break;
    case 256:
        return "#edcc61";
        break;
    case 512:
        return "#9c0";
        break;
    case 1024:
        return "#3365a5";
        break;
    case 2048:
        return "#09c";
        break;
    case 4096:
        return "#a6bc";
        break;
    case 8192:
        return "#93c";
        break;
    }
    return "black";
}
//设置颜色的函数
function getColor (){
 var arr = document.getElementsByClassName('news');
  for(var i=0;i<arr.length;i++){
       arr[i].style.backgroundColor=setColor(parseInt(arr[i].innerText));
  }
}
    </script>
</body>
</html>

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值