Snake6(结束),操作多个 div 之间不会互重叠,若铺满一行,便自动消除。

从七个基本方块中,随机取一个,以600毫秒的速度,匀速从容器顶部开始下落,每次下落 20px。
若方块的底部,触碰到容器的底部,或触碰到其他方块,便停下来并变成灰色。
若下落的方块正好铺满一行,便自动消除该行。
然后再从七个基本方块中,随机取一个继续下落,周而复始。

关键点一:碰到其他方块变成灰色

在check函数里面添加overlap标识是否碰到其他块。这个的原理就是,在方块变成灰色的时候,根据方块变灰在屏幕中的位置组合为键,在container里面存一个标记。这样一来,检查当前下落的方块图形是否碰到其他方块图形就很简单了,只要判断当前方块图形的所有方块的左上角坐标是否在container里面拥有标识,如果check之后当前正在下落的方块图形与存在标识的坐标一致,那么就说明会发送同一个块的左上角坐标重叠,也就是碰撞,此时检查不通过,overlap为true。
完成后的完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <title>Snake</title>
    <style type="text/css">
        .activityModel { margin: 1px; width: 19px; height: 19px;background: red;position: absolute; }
        /*.container { margin: 1px; top: 0px;left: 0px; width: 200px; height: 360px; background: black; position: absolute; }*/
        .stationaryModel { margin: 1px; width: 19px; height: 19px; background: gray; position: absolute; }
        .container { margin: 0px; top: 0px;left: 0px; width: 201px; height: 361px; background: black; position: absolute; }
    </style>
    <script type="text/javascript">
        var SHAPES = [
            [0, 1, 1, 1, 2, 1, 3, 1],
            [1, 0, 1, 1, 1, 2, 2, 2],
            [2, 0, 2, 1, 2, 2, 1, 2],
            [0, 1, 1, 1, 1, 2, 2, 2],
            [1, 2, 2, 2, 2, 1, 3, 1],
            [1, 1, 2, 1, 1, 2, 2, 2],
            [0, 2, 1, 2, 1, 1, 2, 2]
        ];
        var x = 3; 
        var y = 0;
        var size = 20;          
        var shape = [];
        var rowCount=18;
        var colCount=10;
        var speed = 600;
        var intervalId;
        var intervalId2;
        var container = {};
        
        function init(){    
            
            create();
            show();  //根据shape数组坐标排列组合创建的4个方块为方块图形

            //绑定键盘事件
            document.onkeydown = function(e){
                var e= e || window.event;
                switch(e.keyCode){
                    case 32: //space
                        quickDown();
                        break;
                    case 38: //rotate
                        rotate(0,-1);
                        break;
                    case 40: //down
                        move(0,1);
                        break;
                    case 37: //left
                        move(-1,0);
                        break;
                    case 39: //right
                        move(1,0);
                        break;      
                }
            }

            // 方块开始下降
            intervalId = setInterval("move(0,1)",speed);
        }
        
        // 随机获取一个方块数组
        var randomShape = function(){
            shape = SHAPES[Math.floor(Math.random() * 7)];
        }

        // 创建4个方块
        var create = function(){
            randomShape();
            for (var i=0;i<4;i++){
                var div = document.createElement("div");
                div.className = "activityModel";
                document.body.appendChild(div);
            }
        }

        //根据shape数组坐标排列组合创建的4个方块为方块图形
        var show = function(){
            var divs = document.getElementsByClassName("activityModel");
            for(var j=0,index=0,len=divs.length;j<len,index<8;j++){
                divs[j].style.left = (shape[index++]+x)*size +"px";
                divs[j].style.top = (shape[index++]+y)*size +"px";
            }
        }

        // 移动方块
        var move = function(a,b){
            //如果没有越界就更新相对位置,并按照新的相对位置渲染方块图形
            if(check(x+a,y+b,shape)){
                x += a;
                y += b;
                show();
            } else {
                if ( b == 0 ) return;
                fix();
                create();
                show();
                clearInterval(intervalId2);
            }
        }

        // 快速下落
        var quickDown = function() {
            intervalId2 = setInterval("move(0, 1)", 0);
        }

        // 旋转方块
        var rotate = function() {
            newShape = [shape[1], 3 - shape[0], shape[3], 3 - shape[2], shape[5], 3 - shape[4], shape[7], 3 - shape[6]];
            if(!check(x,y,newShape))  return;
            shape = newShape;
            show();
        }

        // 固定方块,变成灰色
        var fix = function(){
            var divs = document.getElementsByClassName("activityModel");
            for(var i = divs.length -1;i >= 0;i--){
                divs[i].className = "stationaryModel";
            }
            for(var j=0,index=0,len=divs.length;j<len,index<8;j++){
                var px = shape[index++]+x;
                var py = shape[index++]+y;
                // if ( j < 4)
                // {
                //  divs[j].className = "stationaryModel";
                // }
                container[px + "_" + py] = "has_gray_box";
            }
            x = 3;
            y = 0;
        }

        var check = function(x,y,shape){
            var most_left = colCount;
            var most_right = 0;
            var most_top = rowCount;
            var most_bottom = 0;
            var overlap = false;
            for(var i=0;i<8;i+=2){
                // 记录最左边水平坐标
                if(shape[i]<most_left){
                    most_left=shape[i];
                }
                // 记录最右边水平坐标
                if(shape[i]>most_right){
                    most_right=shape[i];
                }
                // 记录最上边垂直坐标
                if(shape[i+1]<most_top){
                    most_top=shape[i+1];
                }
                // 记录最下边垂直坐标
                if(shape[i+1]>most_bottom){
                    most_bottom=shape[i+1];
                }
                // 判断方块之间是否重叠,就是判断当前下落的方块每一个左上角坐标是否与已经变成灰色的方块左上角坐标存在重叠
                var px = shape[i] + x;
                var py = shape[i+1] + y;
                if (container[px + "_" + py]){
                    overlap = true;
                }
            }

            if( (most_right+x+1) > colCount || (most_left+x)< 0 || (most_bottom+y+1)>rowCount || (most_top+y)<0 || overlap ){
                return false;
            }
            return true;
        }
    </script>
</head>
<body onload="init()">
    <div class="container"></div>
</body>
</html>

有个隐藏的bug,就是一直按回车,方块会卡在空中。

关键点二:铺满一行就消除

添加findFull函数
思路就是前面我们在container存储了每个灰色左上角坐标的标识。我们遍历每一行,如果该行左上角坐标有在container对应的标识且达到列数,说明该行每一个方块都是灰色,于是调用removeLine函数清除该行。
注意:两大块的注释代码,我们在前面碰撞检测基础上继续添加消除功能,反而连碰撞检测效果都没了,于是有了两大块的注释代码。可以对比注释部分与非注释部分,比较区别。

完整源码:

<!DOCTYPE html>
<html>
<head>
    <title>Snake</title>
    <style type="text/css">
        .activityModel { margin: 1px; width: 19px; height: 19px;background: red;position: absolute; }
        /*.container { margin: 1px; top: 0px;left: 0px; width: 200px; height: 360px; background: black; position: absolute; }*/
        .stationaryModel { margin: 1px; width: 19px; height: 19px; background: gray; position: absolute; }
        .container { margin: 0px; top: 0px;left: 0px; width: 201px; height: 361px; background: black; position: absolute; }
    </style>
    <script type="text/javascript">
        var SHAPES = [
            [0, 1, 1, 1, 2, 1, 3, 1],
            [1, 0, 1, 1, 1, 2, 2, 2],
            [2, 0, 2, 1, 2, 2, 1, 2],
            [0, 1, 1, 1, 1, 2, 2, 2],
            [1, 2, 2, 2, 2, 1, 3, 1],
            [1, 1, 2, 1, 1, 2, 2, 2],
            [0, 2, 1, 2, 1, 1, 2, 2]
        ];
        var x = 3; 
        var y = 0;
        var size = 20;          
        var shape = [];
        var rowCount=18;
        var colCount=10;
        var speed = 600;
        var intervalId;
        var intervalId2;
        var shapeDiv= [];
        var container = {};
        
        function init(){    
            
            create();
            show();  //根据shape数组坐标排列组合创建的4个方块为方块图形

            //绑定键盘事件
            document.onkeydown = function(e){
                var e= e || window.event;
                switch(e.keyCode){
                    case 32: //space
                        quickDown();
                        break;
                    case 38: //rotate
                        rotate(0,-1);
                        break;
                    case 40: //down
                        move(0,1);
                        break;
                    case 37: //left
                        move(-1,0);
                        break;
                    case 39: //right
                        move(1,0);
                        break;      
                }
            }

            // 方块开始下降
            intervalId = setInterval("move(0,1)",speed);
        }
        
        // 随机获取一个方块数组
        var randomShape = function(){
            shape = SHAPES[Math.floor(Math.random() * 7)];
        }

        // 创建4个方块
        var create = function(){
            x = 3;
            y = 0;
            shapeDiv = [];
            randomShape();
            for (var i=0;i<4;i++){
                var div = document.createElement("div");
                div.className = "activityModel";
                shapeDiv[i] = div;
                document.body.appendChild(div);
            }
        }

        //根据shape数组坐标排列组合创建的4个方块为方块图形
        var show = function(){
            var divs = document.getElementsByClassName("activityModel");
            for(var j=0,index=0,len=divs.length;j<len,index<8;j++){
                divs[j].style.left = (shape[index++]+x)*size +"px";
                divs[j].style.top = (shape[index++]+y)*size +"px";
            }
        }

        // 移动方块
        var move = function(a,b){
            //如果没有越界就更新相对位置,并按照新的相对位置渲染方块图形
            if(check(x+a,y+b,shape)){
                x += a;
                y += b;
                show();
            } else {
                if ( b == 0 ) return;
                fix();
                create();
                show();
                clearInterval(intervalId2);
            }
        }

        // 快速下落
        var quickDown = function() {
            intervalId2 = setInterval("move(0, 1)", 0);
        }

        // 旋转方块
        var rotate = function() {
            newShape = [shape[1], 3 - shape[0], shape[3], 3 - shape[2], shape[5], 3 - shape[4], shape[7], 3 - shape[6]];
            if(!check(x,y,newShape))  return;
            shape = newShape;
            show();
        }

        // // 固定方块,变成灰色
        // var fix = function(){
        //  var divs = document.getElementsByClassName("activityModel");
        //  for(var i = divs.length -1;i >= 0;i--){
        //      divs[i].className = "stationaryModel";
        //  }
        //  for(var j=0,index=0,len=divs.length;j<len,index<8;j++){
        //      var px = shape[index++]+x;
        //      var py = shape[index++]+y;
        //      // if ( j < 4)
        //      // {
        //      //  divs[j].className = "stationaryModel";
        //      // }
        //      if ( j < 4){
        //          container[px + "_" + py] = shapeDiv[j];
        //      }
        //  }
        //  findFull();
        // }

        // 固定方块,变成灰色,缓存到容器中
        var fix = function() {
          var divs = document.getElementsByClassName("activityModel");
          for (var i = divs.length - 1; i >= 0; i--) {
            var px = shape[2 * i + 1] + y;
            var py = shape[2 * i] + x;
            container[px + "_" + py] = shapeDiv[i];
            divs[i].className = "stationaryModel";
          }
          findFull();
        }

         // 遍历整个容器,判断是否可以消除
        var findFull = function() {
          for (var m = 0; m < rowCount; m++) {
            var count = 0;
            for (var n = 0; n < colCount; n++) {
              if (container[m + "_" + n])
                count++;
            }
            if (count === colCount) {
              removeLine(m);
            }
          }
        }

        // 消除指定一行方块
        var removeLine = function(rowCount) {
          // 移除一行方块
          for (var n = 0; n < colCount; n++)
            document.body.removeChild(container[rowCount + "_" + n]);
          // 把所消除行上面所有的方块下移一行
          for (var i = rowCount; i > 0; i--) {
            for (var j = 0; j < colCount; j++) {
              container[i + "_" + j] = container[(i - 1) + "_" + j]
              if (container[i + "_" + j])
                container[i + "_" + j].style.top = i * size + "px";
            }
          }
        }

        var check = function(x,y,shape){
            var most_left = colCount;
            var most_right = 0;
            var most_top = rowCount;
            var most_bottom = 0;
            var overlap = false;

            var divs = document.getElementsByClassName("activityModel");
            for (var i = divs.length - 1; i >= 0; i--) {
                // 记录方块最左边坐标
                if (shape[2 * i] < most_left)
                  most_left = shape[2 * i];
                // 记录方块最右边坐标
                if (shape[2 * i] > most_right)
                  most_right = shape[2 * i];
                // 记录方块最上边坐标
                if (shape[2 * i + 1] < most_top)
                  most_top = shape[2 * i + 1];
                // 记录方块最下边坐标
                if (shape[2 * i + 1] > most_bottom)
                  most_bottom = shape[2 * i + 1];
                // 判断方块之间是否重叠
                var px = shape[2 * i + 1] + y;
                var py = shape[2 * i] + x;
                if (container[px + "_" + py])
                  overlap = true;
            }

            // for(var i=0;i<8;i+=2){
            //  // 记录最左边水平坐标
            //  if(shape[i]<most_left){
            //      most_left=shape[i];
            //  }
            //  // 记录最右边水平坐标
            //  if(shape[i]>most_right){
            //      most_right=shape[i];
            //  }
            //  // 记录最上边垂直坐标
            //  if(shape[i+1]<most_top){
            //      most_top=shape[i+1];
            //  }
            //  // 记录最下边垂直坐标
            //  if(shape[i+1]>most_bottom){
            //      most_bottom=shape[i+1];
            //  }
            //  // 判断方块之间是否重叠,就是判断当前下落的方块每一个左上角坐标是否与已经变成灰色的方块左上角坐标存在重叠
            //  var px = shape[i] + x;
   //           var py = shape[i+1] + y;
   //           if (container[px + "_" + py]){
   //                   overlap = true;
   //           }
            // }

            if( (most_right+x+1) > colCount || (most_left+x)< 0 || (most_bottom+y+1)>rowCount || (most_top+y)<0 || overlap ){
                return false;
            }
            return true;
        }
    </script>
</head>
<body onload="init()">
    <div class="container"></div>
</body>
</html>

代码传送门:https://github.com/xiaohuacc/snake/blob/index006/index006.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容