失败且未完成的俄罗斯方块
分析设计俄罗斯方块
1、分析
对俄罗斯方块的功能和行为进行分析
- 操作 1、左右移动方块 2、翻转方块 3、方块急速下降;
- 判断 1、方块可移动区域判断 2、消除判断;
- 功能块 1、移动方块的功能模块 2、关联小方块的功能对象 fObj 3、给对象 fObj 的 xLength、ySpeed 赋值的赋值模块;
- 步骤 1、创建地图,用二维数组来存储地图,地图存储数据; 1为有小方块占用,0为空意味着小方块可以移动至该位置;
2、具体步骤
1.写个快速创建元素的方法
$.createEle=function(params){
var tagName=params.tagName||'div';
var id=params.id||'';
var className=params.className||'';
var content=params.content||'';
var css=params.css||{};
var dom=document.createElement(tagName);
if(id!=''){dom.id=id};
if(className!=''){dom.className=className};
if(content!=''){dom.innerHTML=content};
for(var o in css){
dom.style[o]=css[o];
}
return dom;
};
2.创建地图渲染器
var mapCtrl = (function () {
var map=[];
var cellWidth=20;
var fillMap = function (mapWidth,mapHeight) {
// 创建地图
for (var i = 0; i < mapHeight; i++) {
var _row = [];
for (var j = 0; j < mapWidth;j++) {
_row.push(0);
};
map.push(_row);
};
};
var createMapDom=function(){
var _width=cellWidth*map[0].length;
var _height=cellWidth*map.length;
var divBox=$.createEle({tagName:'div',className:'box-div',id:'mapBox',css:{width:_width+'px',height:_height+'px'}});
for(var i=0,len=map.length;i<len;i++){
var rowDiv=$.createEle({tagName:'div',className:'row-div',css:{position:'absolute',display:'flex',top:i*cellWidth+'px'}});
for(var j=0,len1=map[0].length;j<len1;j++){
var cellDiv=$.createEle({tagName:'div',className:'cell cell-white',css:{width:cellWidth+'px',height:cellWidth+'px'}});
if(i==0){cellDiv.className=cellDiv.className+' cell-top' }
if(j==0){cellDiv.className=cellDiv.className+' cell-left' }
if(i==(len-1)){cellDiv.className=cellDiv.className+' cell-bottom' }
if(j==(len1-1)){cellDiv.className=cellDiv.className+' cell-right' }
rowDiv.appendChild(cellDiv);
}
divBox.appendChild(rowDiv);
}
document.body.appendChild(divBox);
};
var F={};
F.init=function(){
fillMap(12,18);
createMapDom();
};
// 根据数组来重新渲染地图,改变地图的 className
F.renderMap=function(){
var rowCells=$('.box-div .row-div');
for(var i=0,len1=map.length;i<len1;i++){
for(var j=0,len2=map[0].length;j<len2;j++){
var cell=rowCells[i].childNodes[j];
if(map[i][j]==0){
if(cell.className.indexOf(' cell-select')!=-1){
cell.className=cell.className.replace(' cell-select','');
}
}else{
if(cell.className.indexOf(' cell-select')==-1){
cell.className=cell.className+' cell-select';
}
}
}
}
};
// 获取地图
F.getMap=function(){
return map;
};
// 检测位置是否存在俄罗斯方块
F.checkState = function (cell) {
for(var i=0,len=cell.length;i<len;i++){
if (map[cell[i][0]-1][cell[i][1]-1] != 0) {
return false;
}else{
return true;
}
}
};
// 检测点位
F.checkSingleState=function(params){
if(params.a>map.length||params.b>map[0].length){
return false;
}
return map[params.a-1][params.b-1] == 0;
}
// 显示俄罗斯方块
F.showCell=function(cell,status){
for(var i=0,len=cell.length;i<len;i++){
F.changeState({ a: cell[i][0], b: cell[i][1], status: status });
}
}
// 改变地图的显示
F.changeState=function(params){
// map[a][b] 代表多少a行,b列 | status:1 有小方块; 0:无小方块
map[(params.a - 1)][(params.b - 1)] = params.status;
};
// 再地图上创建一个新的俄罗斯方块
F.receiveCell = function (cell) {
// 步骤:1、接受cell 2、计算起始偏移位置,并将新的 cell 返回,如果超出,则返回 false,游戏结束
var _dis = Math.floor((map[0].length - cell.length) / 2);
for (var i = 0, len = cell.length; i < len; i++) {
cell[i][1] += _dis;
};
if (F.checkState(cell)) {
for (var i = 0, len = cell.length; i < len; i++) {
F.changeState({ a: cell[i][0], b: cell[i][1], status: 1 });
};
return cell;
} else {
return false;
}
};
return F;
})();
mapCtrl.init();
3.创建一个控制俄罗斯方块下落、方向等操作的控制器
var cellCtrl=(function(){
var cell=[];
// 方块形体集合
var cells=[
[[1,1],[1,2],[1,3],[1,4]] // 长条 ----
,[[1,1],[1,2],[2,1],[2,2]] // 方块 ==
,[[1,1],[2,1],[2,2],[2,3]] // 左7 =_ _
,[[2,1],[2,2],[1,3],[2,3]] // 右7 _ _=
,[[1,1],[1,2],[2,2],[2,3]] // -=_
,[[2,1],[1,2],[2,2],[1,3]] // _=-
];
var F={};
F.random=function(){
var index=Math.floor(Math.random()*6+1);
for(var i=0,len=cells[(index-1)].length;i<len;i++){
cell.push(cells[(index-1)][i]);
}
cell=mapCtrl.receiveCell(cell);
if(!cell||cell==[]){
alert('游戏结束');
}
mapCtrl.renderMap();
}
F.left = function () {
var newCell = [];
for(var i=0,len=cell.length;i<len;i++){
var a=cell[i][0],b=cell[i][1]-1;
var f=true;
for(var j=0,len2=cell.length;j<len2;j++){
if(a==cell[j][0]&&b==cell[j][1]){
f=false;break;
}
}
if(f){
var obj={};obj.a=a;obj.b=b;
newCell.push(obj);
}
}
var ff=true;
for(var i=0,len=newCell.length;i<len;i++){
if(!mapCtrl.checkSingleState(newCell[i])){
ff=false;
break;
}
}
if(ff){
mapCtrl.showCell(cell,0);
for(var i=0,len=cell.length;i<len;i++){
cell[i][1]-=1;
};
mapCtrl.showCell(cell,1);
mapCtrl.renderMap();
}
};
F.right=function(){
var newCell = [];
for(var i=0,len=cell.length;i<len;i++){
var a=cell[i][0],b=cell[i][1]+1;
var f=true;
for(var j=0,len2=cell.length;j<len2;j++){
if(a==cell[j][0]&&b==cell[j][1]){
f=false;break;
}
}
if(f){
var obj={};obj.a=a;obj.b=b;
newCell.push(obj);
}
}
var ff=true;
for(var i=0,len=newCell.length;i<len;i++){
if(!mapCtrl.checkSingleState(newCell[i])){
ff=false;
break;
}
}
if(ff){
mapCtrl.showCell(cell,0);
for(var i=0,len=cell.length;i<len;i++){
cell[i][1]+=1;
};
mapCtrl.showCell(cell,1);
mapCtrl.renderMap();
}
};
F.top = function () { };
F.down = function () {
if (F.isDown()) {
mapCtrl.showCell(cell, 0);
for (var i = 0, len = cell.length; i < len; i++) {
cell[i][0] += 1;
};
mapCtrl.showCell(cell, 1);
}
if (F.isDown()) {
mapCtrl.showCell(cell, 0);
for (var i = 0, len = cell.length; i < len; i++) {
cell[i][0] += 1;
};
mapCtrl.showCell(cell, 1);
}
mapCtrl.renderMap();
};
F.isDown=function(){
var newCell = [];
for(var i=0,len=cell.length;i<len;i++){
var a=cell[i][0]+1,b=cell[i][1];
var f=true;
for(var j=0,len2=cell.length;j<len2;j++){
if(a==cell[j][0]&&b==cell[j][1]){
f=false;break;
}
}
if(f){
var obj={};obj.a=a;obj.b=b;
newCell.push(obj);
}
}
var ff=true;
for(var i=0,len=newCell.length;i<len;i++){
if(!mapCtrl.checkSingleState(newCell[i])){
ff=false;
break;
}
}
return ff;
};
F.init = function () {
F.random();
setInterval(function(){
if (F.isDown()) {
mapCtrl.showCell(cell, 0);
for (var i = 0, len = cell.length; i < len; i++) {
cell[i][0] += 1;
};
mapCtrl.showCell(cell, 1);
mapCtrl.renderMap();
}else{
F.random();
}
},500);
}
return F;
})();
4.剩余的css,js,html
<style>
.box-div{
border: 2px double #333;
position: relative;
}
.cell{
box-sizing: border-box;
}
.cell-white{
/* border: 1px dotted #333; */
border-right: 1px dotted #333;
border-bottom: 1px dotted #333;
}
.cell-bottom{
border-bottom: none;
}
.cell-top{
border-top:none;
}
.cell-left{
border-left: none;
}
.cell-right{
border-right:none;
}
.cell-select{
background: red;
border: 1px solid #fff;
}
</style>
<body>
<div>
<button id="start">开始</button>
<button class="ctrl-btn" id="ctrlBtn1">左</button>
<button class="ctrl-btn" id="ctrlBtn2">右</button>
<button class="ctrl-btn" id="ctrlBtn3">上</button>
<button class="ctrl-btn" id="ctrlBtn4">下</button>
</div>
<script src="../js/jquery-3.3.1.min.js"></script>
<script>
$('#start').click(function(){
cellCtrl.random();
});
$('#ctrlBtn1').click(function(){
cellCtrl.left();
});
$('#ctrlBtn2').click(function(){
cellCtrl.right();
});
$('#ctrlBtn4').click(function(){
cellCtrl.down();
});
</script>
...
</body>
控制台输入:cellCtrl.init();进行调试。
3、现象
1、连续出现两次相同的方块直接游戏结束;
由于未使用对象的属性来存储方块的坐标,而是使用了数组存储的。导致了,数组坐标变化的时候,方块模板亦随着变化。
总结
1、使用数组存储坐标太容易出错了,尤其是我这种数组中的元素还是数组的情况。其值太容易在不经意间改变。
2、明天使用对象来记录值变化应该就可以完成俄罗斯方块
3、然后再比较网上的实现方法再总结下