之前已经建立好了基本的结构,现在可以真正进入设计编码阶段,在此我们建立一个js类,专门用于控制方块的移动和反转,代码如下
function MoveShape(controls) {
this.controls = controls;
return this;
}
MoveShape.prototype = {
constructor: MoveShape,
turnShape: function () {
var list = this.getCurrentActivePiece();
var currentNextTurn = list.infos[0].NextTurn;
var currentTurn = list.infos[0].CurrentTurn;
if (currentNextTurn == "O") return;//对于方块不做处理
//获取翻转的下一个图形
var nextShape = tetrisShape[currentNextTurn];
//获取当前的形状
var currentShape = tetrisShape[currentTurn];
//获取翻转范围
var region = this.getShapeRegion(list, currentShape);
//检查范围是否超出
if (region.MinI < 0 || region.MinJ < 0 || region.MaxI > (map.Row - 1) || region.MaxJ > (map.Column - 1)) {
return;
}
//开始翻转
this.turn(region, list, nextShape);
},
turn: function (region, list, nextShape) {
var currentBackColor = list.infos[0].BackColor;
var mini = region.MinI == 0 ? region.MinI : region.MinI - 1;
var startIndex = map.column * mini;
var maxi = region.MaxI < (map.row - 1) ? region.MaxI + 1 : region.MaxI;
var endIndex = map.column * maxi;
if (startIndex < 0) return;
//检查是否可以翻转
var checkCount = 0;
for (var i = startIndex; i < endIndex; i++) {
var elem = base.getAttributeValue(this.controls[i]);
if (elem.I >= region.MinI && elem.I <= region.MaxI && elem.J >= region.MinJ && elem.J <= region.MaxJ) {
var a = elem.I - region.MinI;
var b = elem.J - region.MinJ;
var t = nextShape.Shape[a][b];
if (t == 1) {
checkCount++;
}
var count = this.checkPiece(list.infos, elem);
if (count == 0) {
if (elem.Val == 1 && !elem.IsActive) {
return;
}
}
}
}
if (checkCount < 4) {
return;
}
//重置以前的图形
for (i = 0; i < list.infos.length; i++)
{
var info = list.infos[i];
info.Val = 0;
info.IsActive = false;
info.BackColor = map.mapColor;
info.NextTurn = "";
info.CurrentTurn = "";
list.pieces[i].className = map.mapColor;
base.setAttributeValue(list.pieces[i], info);
}
//开始翻转
for (i = startIndex; i < endIndex; i++) {
elem = base.getAttributeValue(this.controls[i]);
if (elem.I >= region.MinI && elem.I <= region.MaxI && elem.J >= region.MinJ && elem.J <= region.MaxJ)
{
var x = elem.I - region.MinI;
var y = elem.J - region.MinJ;
var num = nextShape.Shape[x][y];
if (num == 1)
{
var panel = this.controls[i];
elem.Val = 1;
elem.IsActive = true;
elem.BackColor = currentBackColor;
elem.NextTurn = nextShape.NextTurn;
elem.CurrentTurn = nextShape.CurrentTurn;
panel.className = currentBackColor;
base.setAttributeValue(panel, elem);
}
}
}
},
checkPiece: function(infos, data) {
var count = 0;
for (var index in infos) {
if (infos[index].I == data.I && infos[index].J == data.J) {
count++;
}
}
return count;
},
getMinOrMaxI: function(infos, status) {
var tmp = [];
for (var j = 0; j < infos.length; j++) {
tmp.push(infos[j].I);
}
return status ? Math.min.apply(null, tmp) : Math.max.apply(null, tmp);
},
getMinOrMaxJ: function (infos, status) {
var tmp = [];
for (var j = 0; j < infos.length; j++) {
tmp.push(infos[j].J);
}
return status ? Math.min.apply(null, tmp) : Math.max.apply(null, tmp);
},
resetDiv: function() {
var len = this.controls.length;
for (var i = 0; i < len; i++) {
var piece = this.controls[i];
var data = base.getAttributeValue(piece);
piece.className = map.mapColor;
data.Val = 0;
data.IsActive = false;
base.setAttributeValue(piece, data);
}
},
getCurrentActivePiece: function() {
var pieces = [];
var infos = [];
var count = this.controls.length;
for (var i = 0; i < count; i++) {
var piece = this.controls[i];
var data = base.getAttributeValue(piece);
if (data.IsActive) {
pieces.push(piece);
infos.push(data);
if (infos.length == 4) {
break;
}
}
}
return { "pieces": pieces, "infos": infos };
},
getShapeRegion: function (list, currentShape) {
var maxI = this.getMinOrMaxI(list.infos,false);
var minI = this.getMinOrMaxI(list.infos,true);
var maxJ = this.getMinOrMaxJ(list.infos, false);
var minJ = this.getMinOrMaxJ(list.infos, true);
maxI += currentShape.Offset.Bottom;
minI -= currentShape.Offset.Top;
maxJ += currentShape.Offset.Right;
minJ -= currentShape.Offset.Left;
return {
MaxI: maxI,
MaxJ: maxJ,
MinI: minI,
MinJ: minJ
};
},
getMoveList: function(orientation) {
var list = this.getCurrentActivePiece();
list.nextShspe = this.getNextShspe(orientation, list.infos);
return list;
},
getNextShspe: function(orientation, infos) {
var minI = this.getMinOrMaxI(infos, true);
var num = minI == 0 ? minI : minI - 1;
var startIndex = map.column * num;
var count = this.controls.length;
var nextInfo = [];
var nextPiece = [];
var status = false;
for (var index in infos) {
var info = infos[index];
for (var i = startIndex; i < count; i++) {
var elem = this.controls[i];
var data = base.getAttributeValue(elem);
switch (orientation) {
case "down":
status = data.I == (info.I + 1) && data.J == info.J;
break;
case "left":
status = data.I == info.I && (data.J + 1) == info.J;
break;
case "right":
status = data.I == info.I && (data.J - 1) == info.J;
break;
}
if (status) {
nextInfo.push(data);
nextPiece.push(this.controls[i]);
break;
}
}
}
return { "nextInfos": nextInfo, "nextPieces": nextPiece };
},
fixedDiv: function(list) {
var count = list.infos.length;
for (var i = 0; i < count; i++) {
var elem = list.infos[i];
var panel = list.pieces[i];
elem.IsActive = false;
base.setAttributeValue(panel, elem);
}
},
exchangeStyle: function(list) {
var currentBackColor = list.infos[0].BackColor;
var currentNextTurn = list.infos[0].NextTurn;
var currentTurn = list.infos[0].CurrentTurn;
var currentCount = list.infos.length;
var nextCount = list.nextShspe.nextInfos.length;
for (var i = 0; i < currentCount; i++) {
var data = list.infos[i];
data.Val = 0;
data.IsActive = false;
data.BackColor = map.mapColor;
data.NextTurn = "";
data.CurrentTurn = "";
base.setAttributeValue(list.pieces[i], data);
list.pieces[i].className = map.mapColor;
}
for (i = 0; i < nextCount; i++) {
data = list.nextShspe.nextInfos[i];
data.Val = 1;
data.IsActive = true;
data.BackColor = currentBackColor;
data.NextTurn = currentNextTurn;
data.CurrentTurn = currentTurn;
base.setAttributeValue(list.nextShspe.nextPieces[i], data);
list.nextShspe.nextPieces[i].className = currentBackColor;
}
},
cleanOutPanel: function() {
//保存需要清除的panel
var elems = [];
//保存ElementInfo
var infos = [];
var row = map.row-1;
var column = map.column;
for (var i = row; i >= 0; i--)//反向遍历,从最后一行开始
{
var addStatus = true;
var checkNum = 0;
for (var j = 0; j < column; j++)
{
//检查此行是否已经填充满
var index = i*column + j;
//var elem = (ElementInfo) Controls[index].Tag;
var elem = base.getAttributeValue(this.controls[index]);
if (elem.Val != 0) continue;
checkNum++;
addStatus = false;
}
if (checkNum == column)
{
//此行没有一个被填充的div,表示已经遍历完毕
break;
}
if (!addStatus) continue;
//保存可以被清除的panel
for (j = 0; j < column; j++)
{
index = i * column + j;
elems.push(this.controls[index]);
}
}
// 清除一行中全部被填充的div
for (var panel in elems)
{//清除一行中全部被填充的div
var info = base.getAttributeValue(elems[panel]);
info.Val = 0;
info.IsActive = false;
info.BackColor = map.mapColor;
info.NextTurn = "";
info.CurrentTurn = "";
elems[panel].className = map.mapColor;
base.setAttributeValue(elems[panel], info);
infos.push(info);
}
this.moveDownPanel(infos);
},
isContain: function(arr,obj) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == obj) {
return true;
}
}
return false;
},
moveDownPanel: function (panels) {
if (panels.length <= 0) return;
var row = map.row-1;
var column = map.column;
var me = this;
function tmpFunc() {
var t = [];
for (var k = 0; k < panels.length; k++) {
if (!me.isContain(t, panels[k].I)) {
t.push(panels[k].I);
}
}
return t.sort(function(x, y) {
if (x > y)
return -1;
if (x < y)
return 1;
});
}
var rows = tmpFunc();
var count = rows.length;
var indexs = [];
var spans = [];
if (count == 1)
{
indexs.push(rows[0]);
spans.push(1);
}
else if (count == 4)
{
indexs.push(rows[0]);
spans.push(4);
}
else if (count == 2)
{
var tmp = rows[0] - rows[1];
if (tmp == 1)
{
indexs.push(rows[0]);
spans.push(2);
}
else
{
indexs.push(rows[0]);
spans.push(1);
indexs.push(rows[1] + 1);
spans.push(2);
}
}
else if (count == 3)
{
tmp = rows[0] - rows[1];
var tmp1 = rows[1] - rows[2];
if (tmp == tmp1)
{
indexs.push(rows[0]);
spans.push(3);
}
else if (tmp == 1 && tmp1 != 1)
{
indexs.push(rows[0]);
spans.push(2);
indexs.push(rows[2] + 2);
spans.push(3);
}
else if (tmp != 1 && tmp1 == 1)
{
indexs.push(rows[0]);
spans.push(1);
indexs.push(rows[1]+1);
spans.push(3);
}
}
for (var item = 0; item < indexs.length; item++)
{
var status = false;
var idx = indexs[item];
var span = spans[item];
for (var i = row; i >= 0; i--) //反向遍历,从最后一行开始
{
if (i == (idx - span) && !status)
{
status = true;
}
if (status)
{
var checkNum = 0;
var breakStatus = false;
for (var j = 0; j < column; j++)
{
var index = i * column + j;
var panel = this.controls[index];
var info = base.getAttributeValue(panel);
if (info.Val == 1)
{
var nextShape = this.collectionShapeQuery(info, idx);
this.cleanExchangeStyle({
infos: [info],
pieces: [panel],
nextShspe: nextShape
});
}
else
{
checkNum++;
}
if (checkNum == column)
{//发现空行
breakStatus = true;
break;
}
}
if (breakStatus)
{
break;
}
idx--;
}
}
}
},
collectionShapeQuery: function(info, index) {
var nextShape = { nextInfos: [], nextPieces: [] };
var startIndex = map.column * info.I;
var count = this.controls.length;
for (var i = startIndex; i < count; i++) {
var elem = base.getAttributeValue(this.controls[i]);
if (elem.I == index && elem.J == info.J) {
nextShape.nextInfos.push(elem);
nextShape.nextPieces.push(this.controls[i]);
break;
}
}
return nextShape;
},
cleanExchangeStyle: function(list) {
var currentBackColor = list.infos[0].BackColor;
var currentNextTurn = list.infos[0].NextTurn;
var currentTurn = list.infos[0].CurrentTurn;
var currentCount = list.infos.length;
var nextCount = list.nextShspe.nextInfos.length;
for (var i = 0; i < currentCount; i++)
{
var info = list.infos[i];
info.Val = 0;
info.IsActive = false;
info.BackColor = map.mapColor;
info.NextTurn = "";
info.CurrentTurn = "";
list.pieces[i].className = map.mapColor;
base.setAttributeValue(list.pieces[i], info);
}
for (i = 0; i < nextCount; i++)
{
info = list.nextShspe.nextInfos[i];
info.Val = 1;
info.IsActive = false;
info.BackColor = currentBackColor;
info.NextTurn = currentNextTurn;
info.CurrentTurn = currentTurn;
base.setAttributeValue(list.nextShspe.nextPieces[i], info);
list.nextShspe.nextPieces[i].className = currentBackColor;
}
}
};
这样就完成了对方块的控制,好了距离成功又近了一步,下一篇中我们来完成这个游戏。