基于 HTML5 的 WebGL 3D 版俄罗斯方块的示例代码

2019-01-28 21:06:33丽君

生成方块,我的想法是生成多个正方形,将它们组合成我们需要的图形,通过坐标的计算来将它们摆放在相应的位置:

方块生成后,开始对图形进行旋转操作。这其中有两个方案,第一种是将图形的翻转后的图形坐标按顺序保存在数组中,每次改变形状时取数组中的前一组或后一组坐标来进行改变;第二种是使用 ht.Block() 对象将对应的图元组合成一个整体,在变形时只需按对应的方向选择 90° 即可。在这里,我选择了第二中方式,代码如下: 

function createUnit(x, y) { var node = new ht.Node(); node.s({ "shape": "rect", "shape.background": "#D8D8D8", "shape.border.width": 1, "shape.border.color": "#979797" }); node.setPosition(x, y); node.setSize(44, 44); gameDM.add(node); return node; } var block = new ht.Block(); block.addChild(createUnit(552, 133)); block.addChild(createUnit(552, 89)); block.addChild(createUnit(508, 133)); block.addChild(createUnit(596, 133)); block.setAnchor(0.5, 0.75); //设置组合的中心位置, 旋转时将安装此点来进行 block.setPosition(552, 144);

Block 设置中心点 Anchor 如下图:

在设置旋转时,只需使用 setRotation 函数对 block 进行旋转即可:


复制代码
block.setRotation(Math.PI*rotationNum/2); //rotationNum 是一个计数器,保存已经旋转次数,保证每次都是在上一次的基础上旋转90°

方块有了,现在就该让它动起来了。设置定时器,使方块每隔一段时间下降一定距离,并添加键盘的监听事件,以此实现 w:翻转、s:左移动、d:右移动、s:下移的操作,同时为了不使方块移动出边界,在每次位移时都将对坐标进行一次验证:

var offset = 44; var intervalTime = 1000; var topX = 552; var topY = 111; var leftSize = 211, rightSize = 882, bottomSize = 1002; var rotationNum = 0; window.addEventListener('keydown', function(e){   var index = 0;   var maxY = null;   if(e.keyCode == 87){     // up w     rotationNum ++;     block.setRotation(Math.PI*rotationNum/2);     if (!checkRotation(block)) {       rotationNum --;       block.setRotation(Math.PI*rotationNum/2);     }   } else if (e.keyCode == 65) {     // left a     moveBlock('x', -offset, block);   } else if (e.keyCode == 68) {     // right d     moveBlock('x', offset, block);   } else if(e.keyCode == 83){     // down s     moveBlock('y', offset, block);   } }, false); setInterval(function(){   if(!moveBlock("y", offset, block)){     //无法进行位移,创建新的方块     rotationNum = 0; //方块翻转次数归0     block = createNode(blockType); //生成新的方块     blockType = parseInt(Math.random()*100%5); //下一次生成的方块图形   } }, intervalTime); //执行间隔 //移动方块,移动成功时返回:true,无法移动时返回:false function moveBlock(axis, offset, block){   // 移动方块   var ids = [];   var yindexs = [];   var indexArr = new Array();   for(var i = 0; i < block.size(); i ++){     var childNode = block.getChildAt(i);     var childx = childNode.getPosition().x;     var childy = childNode.getPosition().y;     if (yindexs.indexOf(childy) == -1) {       yindexs.push(childy);     }     if(axis === 'x'){       childx += offset;     }else if (axis === 'y') {       childy += offset;     }     // 验证方块的移动是否超出边界     if(childx < leftSize || childx > rightSize || childy > bottomSize){       return false;     }     var obj = new Object();     obj.x = childx;     obj.y = childy;     indexArr.push(obj);     ids.push(childNode.getId());   }   //判断图形位移过程中是否与其他方块触碰   for(var j = 0; j < yindexs.length; j ++){     var indexY = yindexs[j];     if (axis === 'y') {       indexY += offset;     }     //getDatasInRect 方法能获取到一个范围中的所有图元信息     var nodeList = g2d.getDatasInRect({x:233, y:indexY, width:638, height:2}, true, false);     if(nodeList.length > 0){       // 触碰       for(var i = 0; i < nodeList.length; i++){         var x = nodeList.get(i).getPosition().x;         var y = nodeList.get(i).getPosition().y;         var id = nodeList.get(i).getId();         if (ids.indexOf(id) > -1) {           // 位移的图元           continue;         }         for (var k = 0; k < indexArr.length; k++) {           var obj = indexArr[k];           if (obj.x === x && obj.y === y){             // 该停下了             return false;           }         }       }     }   }   var blockX = block.getX();   var blockY = block.getY();   if (axis === 'x') {     blockX += offset;   }else if (axis === 'y') {     blockY += offset;   }   // 方块移动到新的坐标   block.setPosition(blockX, blockY);   return true; } // 验证方块是否可以进行翻转 function checkRotation(block){   for(var i = 0; i < block.getChildren().length; i++){     var node = block.getChildAt(i);     var childx = node.getPosition().x;     var childy = node.getPosition().y;     // 判断翻转后的图形是否会超出范围     if(childx < leftSize || childx > rightSize || childy > bottomSize){       return false;     }   }   return true; }