兼容性
兼容IE10,现代浏览器
效果图
项目结构
tetris
css
tetris.css
js
tetris.js
tetris.html
tetris.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>俄罗斯方块</title>
<link rel="stylesheet" type="text/css" href="css/tetris.css">
</head>
<body>
<div class="container">
<div class="left">
<div id="score-panel" class="score-panel">
<span class="score-label">得分:</span>
<span class="score">0</span>
</div>
<div id="main-panel" class="panel">
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
<div class="panel-cell"></div>
</div>
<div id="fail" class="fail hidden">
<div class="fail-down">失败了</div>
<div class="fail-up">失败了</div>
</div>
</div>
<div class="right">
<div id="preview" class="preview"></div>
<div class="key-summary">
<div class="key-summary-row"><!--
--><div id="left-turn" class="key-summary-show key-summary-left-turn"><span>Q</span> <span>左转</span></div><!--
--><div id="right-turn" class="key-summary-show key-summary-right-turn"><span>E</span> <span>右转</span></div><!--
--></div>
<div class="key-summary-row"><!--
--><div id="left-move" class="key-summary-show key-summary-left-move"><span>A</span> <span>左移</span></div><!--
--><div id="bottom-move" class="key-summary-show key-summary-bottom-move"><span>S</span> <span>下移</span></div><!--
--><div id="right-move" class="key-summary-show key-summary-right-move"><span>D</span> <span>右移</span></div><!--
--></div>
<div class="key-summary-row"><!--
--><div id="pause-restore" class="key-summary-show key-summary-pause-restore"><!--
--><span>SPACE</span> <span class="show-pause-restore">暂停</span><!--
--></div><!--
--></div>
</div>
<div class="start-container"><!--
--><div id="start-normal" class="start start-normal">重新开始</div><!--
--></div>
<div class="start-container"><!--
--><div id="start-random" class="start start-random">随机玩法</div><!--
--></div>
</div>
</div>
</body>
<script type="text/javascript" src="js/tetris.js"></script>
</html>
tetris.css
html,body {height: 100%;}
.container {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 460px;
height: 514px;
background-color: #00AA00;
font-family: "Microsoft YaHei", "微软雅黑", serif;
}
.left {
position: absolute;
left: 0;
top: 0;
width: 244px;
height: 514px;
}
.left .score-panel {
height: 30px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border: 2px solid #202020;
border-bottom: none;
line-height: 28px;
font-size: 16px;
background-color: #00FFFF;
}
.left .score-panel .score-label {
margin-left: 10px;
}
.left .score-panel .score {
font-weight: bold;
}
.left .panel {
position: relative;
left: 0;
top: 0;
overflow: hidden;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border: 2px solid #202020;
height: 484px;
}
.left .panel-cell {
float: left;
width: 24px;
height: 24px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border: 1px solid #f0f0f0;
background-color: #D0D0D0;
}
.left .fail {
position: absolute;
z-index: 3;
width: 160px;
height: 40px;
left: 0;
right: 0;
top: 30px;
bottom: 0;
margin: auto;
text-align: center;
line-height: 40px;
font-size: 30px;
letter-spacing: 8px;
text-indent: 8px;
color: #ffffff;
-webkit-user-select: none;-ms-user-select: none;user-select: none;
}
.left .fail-down {
position: absolute;
width: 100%;
color: #202020;
left: 2px;
top: 2px;
opacity: 0.35;
}
.left .fail-up {
position: absolute;
width: 100%;
left: 0;
top: 0;
text-shadow: 0 0 5px #202020;
}
.left .hidden {
display: none;
}
.right {
position: absolute;
right: 0;
top: 0;
width: 216px;
height: 514px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border: 2px solid #202020;
border-left: none;
background-color: #d5c9f0;
-webkit-user-select: none;-ms-user-select: none;user-select: none;
}
.right .preview {
position: relative;
left: 0;
top: 0;
overflow: hidden;
height: 214px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border-bottom: 2px solid #202020;
}
.right .preview .preview-shape {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.right .preview .preview-cell {
float: left;
width: 24px;
height: 24px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border: 1px solid #d5c9f0;
}
.right .key-summary {
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
border-bottom: 2px solid #202020;
cursor: default;
}
.right .key-summary .key-summary-row {
text-align: center;
margin: 10px 0;
}
.right .key-summary .key-summary-show {
display: inline-block;
height: 36px;
border: 2px solid #5cffa8;
background-color: #122b40;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
padding: 4px 10px;
overflow: hidden;
color: #f0f0f0;
font-size: 14px;
line-height: 24px;
border-radius: 16px;
margin: 0 2px;
cursor: pointer;
}
.right .key-summary .key-summary-left-turn,
.right .key-summary .key-summary-right-turn {
padding: 4px 27px;
}
.right .key-summary .key-summary-pause-restore {
padding: 4px 62px;
background-color: #d58a05;
}
.right .key-summary .down {
line-height: 26px;
}
.right .start-container {
text-align: center;
margin: 18px 0;
}
.right .start {
display: inline-block;
height: 40px;
-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;
padding: 4px 12px;
color: #f0f0f0;
font-size: 18px;
font-weight: bold;
letter-spacing: 4px;
text-indent: 4px;
line-height: 28px;
border: 2px solid #0000FF;
border-radius: 20px;
margin: 0 2px;
cursor: pointer;
}
.right .start.down {
line-height: 30px;
}
.right .start-normal {
background-color: #00e000;
}
.right .start-random {
background-color: #FF00FF;
}
tetris.js
(function (window, document) {
var scoreDom = document.querySelector('#score-panel .score');
var panelCellDoms = document.querySelectorAll('#main-panel .panel-cell');
var previewDom = document.querySelector('#preview');
var failDom = document.querySelector('#fail');
var leftTurn = document.querySelector('#left-turn');
var rightTurn = document.querySelector('#right-turn');
var leftMove = document.querySelector('#left-move');
var bottomMove = document.querySelector('#bottom-move');
var rightMove = document.querySelector('#right-move');
var pauseRestoreDom = document.querySelector('#pause-restore');
var showPauseRestore = pauseRestoreDom.querySelector('.show-pause-restore');
var startNormalDom = document.querySelector('#start-normal');
var startRandomDom = document.querySelector('#start-random');
var mainCells = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
];
var shapes = {
//O
0: {
0: {point: [[1, 1], [1, 1]], x: 0, y: 0},
length: 1, type: 'O', color: '#ff0096'
},
//I
1: {
0: {point: [[1, 1, 1, 1]], x: 1, y: 0},
1: {point: [[1], [1], [1], [1]], x: 0, y: 2},
length: 2, type: 'I', color: '#00ee0c'
},
//T
2: {
0: {point: [[1, 1, 1], [0, 1, 0]], x: 1, y: 0},
1: {point: [[0, 1], [1, 1], [0, 1]], x: 1, y: 1},
2: {point: [[0, 1, 0], [1, 1, 1]], x: 1, y: 1},
3: {point: [[1, 0], [1, 1], [1, 0]], x: 0, y: 1},
length: 4, type: 'T', color: '#ffa905'
},
//L1
3: {
0: {point: [[1, 0], [1, 0], [1, 1]], x: 0, y: 1},
1: {point: [[1, 1, 1], [1, 0, 0]], x: 1, y: 0},
2: {point: [[1, 1], [0, 1], [0, 1]], x: 1, y: 1},
3: {point: [[0, 0, 1], [1, 1, 1]], x: 1, y: 1},
length: 4, type: 'L', color: '#ff000a'
},
//L2
4: {
0: {point: [[0, 1], [0, 1], [1, 1]], x: 1, y: 1},
1: {point: [[1, 0, 0], [1, 1, 1]], x: 1, y: 1},
2: {point: [[1, 1], [1, 0], [1, 0]], x: 0, y: 1},
3: {point: [[1, 1, 1], [0, 0, 1]], x: 1, y: 0},
length: 4, type: 'L', color: '#00d1b4'
},
//S
5: {
0: {point: [[1, 0], [1, 1], [0, 1]], x: 0, y: 1},
1: {point: [[0, 1, 1], [1, 1, 0]], x: 1, y: 0},
length: 2, type: 'S', color: '#0660ff'
},
//Z
6: {
0: {point: [[0, 1], [1, 1], [1, 0]], x: 0, y: 1},
1: {point: [[1, 1, 0], [0, 1, 1]], x: 1, y: 0},
length: 2, type: 'Z', color: '#a745ff'
},
length: 7
};
var Cell = (function () {
function Cell(shape, index, x, y) {
this.shape = shape;
this.index = index;
this.x = x || 0;
this.y = y || 0;
}
Cell.prototype.getX = function () {
return this.x;
};
Cell.prototype.getY = function () {
return this.y;
};
Cell.prototype.setX = function (x) {
this.x = x;
};
Cell.prototype.setY = function (y) {
this.y = y;
};
Cell.prototype.incrX = function (x) {
this.x += x;
};
Cell.prototype.incrY = function (y) {
this.y += y;
};
Cell.prototype.decrX = function (x) {
this.x -= x;
};
Cell.prototype.decrY = function (y) {
this.y += y;
};
return Cell;
})();
var CellUtil = (function () {
var score = 0;
var cellQueue = [];
var currentCell = null;
var isPause = false, isStart = false;
var nextTimeout = null, moveTimeout = null;
var magic = 0, loopEventTime = null;
function Util() {}
Util.prototype.setMagic = function (num) {
magic = num;
};
Util.prototype.getMagic = function () {
return magic;
};
Util.prototype.clearLoopEventTime = function () {
this.setMagic(0);
window.clearTimeout(loopEventTime);
};
Util.prototype.initNormal = function () {
this._clear();
for (var i = 0; i < mainCells.length; i++) {
mainCells[i] = 0;
}
this._init();
};
Util.prototype.initRandom = function () {
this._clear();
var count = 0;
for (var i = 0; i < mainCells.length; i++) {
var act = i < 50 || count >= 9 ? 0 : (Math.random() + 0.15) | 0;
act > 0 ? count++ : count = 0;
mainCells[i] = act;
}
this._init();
};
Util.prototype.pauseOrRestore = function () {
if (!isStart) {
return;
}
if (isPause) {
isPause = false;
showPauseRestore.innerText = '暂停';
this._loopMoveBottom();
} else {
isPause = true;
showPauseRestore.innerText = '恢复';
window.clearTimeout(moveTimeout);
}
};
Util.prototype._clear = function () {
isPause = false;
isStart = true;
this.setMagic(0);
window.clearTimeout(nextTimeout);
window.clearTimeout(moveTimeout);
cellQueue = [];
currentCell = null;
failDom.classList.add('hidden');
scoreDom.innerText = score = 0;
previewDom.innerHTML = '';
showPauseRestore.innerText = '暂停';
};
Util.prototype._alertFail = function () {
isStart = false;
this.setMagic(0);
window.clearTimeout(nextTimeout);
window.clearTimeout(moveTimeout);
cellQueue = [];
currentCell = null;
failDom.classList.remove('hidden');
};
Util.prototype._init = function () {
scoreDom.innerText = 0;
previewDom.innerHTML = '';
for (var i = 0; i < mainCells.length; i++) {
if (mainCells[i] === 1) {
panelCellDoms[i].style.backgroundColor = '#204060';
} else {
panelCellDoms[i].style.backgroundColor = '#D0D0D0';
}
}
this._start();
};
Util.prototype._start = function () {
this.previewCell();
this._next();
};
Util.prototype._next = function () {
var that = this;
window.clearTimeout(nextTimeout);
nextTimeout = window.setTimeout(function () {
currentCell = cellQueue.shift();
that.previewCell();
that._refresh(currentCell, function (cell) {
var shape = cell.shape[cell.index];
var point = shape.point;
var wCnt = point[0].length, hCnt = point.length;
cell.setX(((10 - wCnt) / 2) | 0);
cell.setY(0 - hCnt);
});
if (isPause) {
return;
}
that._loopMoveBottom();
}, 1800);
};
Util.prototype._loopMoveBottom = function () {
var that = this;
window.clearTimeout(moveTimeout);
if (currentCell == null) {
return;
}
var delay = Math.max(1200 - ((score / 10) | 0), 200);
moveTimeout = window.setTimeout(function () {
if (currentCell !== null) {
that.moveToBottom();
that._loopMoveBottom();
}
}, delay);
};
Util.prototype.previewCell = function () {
var cell = this._createCell();
cellQueue.push(cell);
previewDom.innerHTML = '';
var shapeColor = cell.shape.color;
var shape = cell.shape[cell.index];
var point = shape.point;
var previewShape = document.createElement('div');
previewShape.classList.add('preview-shape');
var hCnt = point.length, wCnt = point[0].length;
for (var i = 0; i < hCnt; i++) {
var pointSub = point[i];
for (var j = 0; j < wCnt; j++) {
var previewCell = document.createElement('div');
previewCell.classList.add('preview-cell');
if (pointSub[j] === 1) {
previewCell.style.backgroundColor = shapeColor;
}
previewShape.appendChild(previewCell);
}
}
previewShape.style.width = wCnt * 24 + 'px';
previewShape.style.height = hCnt * 24 + 'px';
previewDom.appendChild(previewShape);
};
Util.prototype._createCell = function () {
var shapesIndex = (Math.random() * shapes.length) | 0;
var shape = shapes[shapesIndex];
var cell = new Cell(shape, (Math.random() * shape.length) | 0);
var subShape = shape[cell.index];
var point = subShape.point;
cell.x = Math.round((10 - point[0].length) / 2);
cell.y = 0 - point.length;
return cell;
};
Util.prototype._refresh = function (cell, func) {
var originalCell = new Cell(cell.shape, cell.index, cell.x, cell.y);
var preIndexes = this.getPanelCellDomIndexes(cell);
var check = func(cell);
var postIndexes = this.getPanelCellDomIndexes(cell);
if (check) {
if (this._isOutBottom(cell) || this._isCover(postIndexes)) {
cell.shape = originalCell.shape;
cell.index = originalCell.index;
cell.setX(originalCell.getX());
cell.setY(originalCell.getY());
this._fixCell(cell);
currentCell = null;
if (this._isFail(originalCell, this._eliminate())) {
this._alertFail();
} else {
this._next();
}
return;
}
} else {
if (originalCell.index === cell.index) {
if (!this._checkMove(cell, postIndexes)) {
cell.shape = originalCell.shape;
cell.index = originalCell.index;
cell.setX(originalCell.getX());
cell.setY(originalCell.getY());
return;
}
} else {
//旋转边缘检查
if (!this._checkRotate(cell)) {
cell.shape = originalCell.shape;
cell.index = originalCell.index;
cell.setX(originalCell.getX());
cell.setY(originalCell.getY());
return;
}
}
}
postIndexes = this.getPanelCellDomIndexes(cell);
var pasIndexes = this.arrayExcept(preIndexes, postIndexes);
this._refreshDom(cell, pasIndexes, postIndexes);
};
Util.prototype._fixCell = function (cell) {
var postIndexes = this.getPanelCellDomIndexes(cell);
for (var i = 0; i < postIndexes.length; i++) {
mainCells[postIndexes[i]] = 1;
}
};
Util.prototype._eliminate = function () {
var indexs = [];
for (var i = 0; i < mainCells.length; i++) {
if (i % 10 === 0) {
if (mainCells[i] === 1) {
indexs.push(i);
} else {
i = ((i / 10 + 1) | 0) * 10 - 1;
}
} else {
if (mainCells[i] === 1) {
indexs.push(i);
} else {
indexs.splice(indexs.length - i % 10);
i = ((i / 10 + 1) | 0) * 10 - 1;
}
}
}
if (!indexs.length) {
return 0;
}
scoreDom.innerText = this._incrScore(indexs.length / 10);
for (var i = 0; i < indexs.length; i++) {
var index = indexs[i];
for (var j = index; j >= 0; j -= 10) {
if (j < 10) {
mainCells[j] = 0;
panelCellDoms[j].style.backgroundColor = '#D0D0D0';
} else {
mainCells[j] = mainCells[j - 10];
panelCellDoms[j].style.backgroundColor = panelCellDoms[j - 10].style.backgroundColor;
}
}
}
return indexs.length / 10;
};
Util.prototype._isFail = function (cell, rows) {
return cell.y + rows < 0;
};
Util.prototype._incrScore = function (rows) {
if (rows === 1) {
score += 10;
} else if (rows === 2) {
score += 20;
} else if (rows === 3) {
score += 40;
} else if (rows === 4) {
score += 80;
}
return score;
};
Util.prototype._checkMove = function (cell, postIndexes) {
if (!this._isInnerMain(cell)) {
return false;
}
//平移边缘检查, 如果无覆盖,则返回true,否则返回false
return !this._isCover(postIndexes);
};
Util.prototype._isOutBottom = function (cell) {
var subShape = cell.shape[cell.index], point = subShape.point;
var hCnt = point.length;
return cell.y + hCnt > 20;
};
Util.prototype._isCover = function (postIndexes) {
//平移边缘检查, 如果无覆盖,则返回true,否则返回false
for (var i = 0; i < postIndexes.length; i++) {
if (mainCells[postIndexes[i]] === 1) {
return true;
}
}
return false;
};
Util.prototype._checkRotate = function (cell) {
//旋转边缘检查, 如果无覆盖,则返回true,否则返回false
var innerMain = this._isInnerMain(cell);
var subShape = cell.shape[cell.index], point = subShape.point;
var hCnt = point.length, wCnt = point[0].length;
if (!innerMain) {
cell.x < 0 ? cell.setX(0) : cell.setX(10 - wCnt);
}
var outBottom = cell.y + hCnt > 20, isBottom = cell.y + hCnt >= 20;
if (outBottom) {
cell.setY(20 - hCnt);
}
var indexes = this.getPanelCellDomIndexes(cell);
var x = cell.x, y = cell.y;
if (innerMain) {
if (x > 0 && this._isCover(indexes) && (cell.shape.type !== 'T' || (cell.shape.type === 'S' || cell.shape.type === 'Z') && cell.index === 0)) {
cell.setY(y);
cell.setX(x - 1);
indexes = this.getPanelCellDomIndexes(cell);
}
if (x + wCnt < 20 && this._isCover(indexes) && (cell.shape.type !== 'T' && cell.shape.type !== 'I' || (cell.shape.type === 'S' || cell.shape.type === 'Z') && cell.index === 1)) {
cell.setY(y);
cell.setX(x + 1);
indexes = this.getPanelCellDomIndexes(cell);
}
}
return !this._isCover(indexes);
};
Util.prototype._isInnerMain = function (cell) {
var shape = cell.shape[cell.index], point = shape.point;
var wCnt = point[0].length;
return cell.x >= 0 && cell.x + wCnt <= 10;
};
Util.prototype._refreshDom = function (cell, pasIndexes, postIndexes) {
for (var i = 0; i < pasIndexes.length; i++) {
panelCellDoms[pasIndexes[i]].style.backgroundColor = '';
}
for (var i = 0; i < postIndexes.length; i++) {
panelCellDoms[postIndexes[i]].style.backgroundColor = cell.shape.color;
}
};
Util.prototype.getPanelCellDomIndexes = function (cell) {
var shape = cell.shape[cell.index], x = cell.x, y = cell.y, point = shape.point;
var panelCellDomIndexes = [];
var hCnt = point.length, wCnt = point[0].length;
for (var i = 0; i < hCnt; i++) {
var pY = i + y;
if (pY < 0 || pY >= 20) {
continue;
}
var pointSub = point[i];
for (var j = 0; j < wCnt; j++) {
var pX = j + x;
if (pX < 0 || pX >= 10) {
continue;
}
if (pointSub[j] === 1) {
panelCellDomIndexes.push(pX + pY * 10);
}
}
}
return panelCellDomIndexes;
};
Util.prototype.arrayExcept = function (arr1, arr2) {
var except = [];
loop:
for (var i = 0; i < arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] === arr2[j]) {
continue loop;
}
}
except.push(arr1[i]);
}
return except;
};
Util.prototype.moveToLeft = function () {
if (currentCell == null || isPause) {
return;
}
var shape = currentCell.shape[currentCell.index], hCnt = shape.point.length;
if (currentCell.y + hCnt < 1) {
return;
}
this._refresh(currentCell, function (cell) {
cell.decrX(1);
return false;
});
};
Util.prototype.moveToRight = function () {
if (currentCell == null || isPause) {
return;
}
var shape = currentCell.shape[currentCell.index], hCnt = shape.point.length;
if (currentCell.y + hCnt < 1) {
return;
}
this._refresh(currentCell, function (cell) {
cell.incrX(1);
return false;
});
};
Util.prototype.moveToBottom = function () {
if (currentCell == null || isPause) {
return;
}
this._refresh(currentCell, function (cell) {
cell.incrY(1);
return true;
});
};
Util.prototype.turnToLeft = function () {
if (currentCell == null || isPause) {
return;
}
var shape = currentCell.shape[currentCell.index], hCnt = shape.point.length;
if (currentCell.y + hCnt < 1) {
return;
}
this._refresh(currentCell, function (cell) {
var shape = cell.shape;
var preCell = shape[cell.index];
cell.index = (cell.index + shape.length - 1) % shape.length;
var postCell = shape[cell.index];
cell.incrX(preCell.x - postCell.x);
cell.incrY(preCell.y - postCell.y);
return false;
});
};
Util.prototype.turnToRight = function () {
if (currentCell == null || isPause) {
return;
}
var shape = currentCell.shape[currentCell.index], hCnt = shape.point.length;
if (currentCell.y + hCnt < 1) {
return;
}
this._refresh(currentCell, function (cell) {
var shape = cell.shape;
var preCell = shape[cell.index];
cell.index = (cell.index + 1) % shape.length;
var postCell = shape[cell.index];
cell.incrX(preCell.x - postCell.x);
cell.incrY(preCell.y - postCell.y);
return false;
});
};
Util.prototype.loopEvent = function (delay) {
var that = this;
loopEventTime = window.setTimeout(function () {
if (magic === 3) {
delay = Math.max(delay - 30, 30);
}
that.loopEvent(delay);
switch (magic) {
case 1:
that.moveToLeft();
break;
case 2:
that.moveToRight();
break;
case 3:
that.moveToBottom();
break;
case 4:
that.turnToLeft();
break;
case 5:
that.turnToRight();
break;
}
}, delay);
};
Util.prototype.keyDown = function (magic) {
if (this.getMagic() !== magic) {
CellUtil.clearLoopEventTime();
CellUtil.setMagic(magic);
switch (magic) {
case 1:
this.moveToLeft();
CellUtil.loopEvent(150);
break;
case 2:
this.moveToRight();
CellUtil.loopEvent(150);
break;
case 3:
this.moveToBottom();
CellUtil.loopEvent(150);
break;
case 4:
this.turnToLeft();
CellUtil.loopEvent(250);
break;
case 5:
this.turnToRight();
CellUtil.loopEvent(250);
break;
}
}
};
return new Util();
})();
document.onkeydown = (function () {
return function (e) {
var code = (e.code || e.key).toLowerCase();
switch (code) {
case 'keyq':
case 'q':
case 'keyw':
case 'w':
case 'arrowup':
case 'up':
CellUtil.keyDown(4);
break;
case 'keye':
case 'e':
CellUtil.keyDown(5);
break;
case 'keya':
case 'a':
case 'arrowleft':
case 'left':
CellUtil.keyDown(1);
break;
case 'keys':
case 's':
case 'arrowdown':
case 'down':
CellUtil.keyDown(3);
break;
case 'keyd':
case 'd':
case 'arrowright':
case 'right':
CellUtil.keyDown(2);
break;
}
document.onkeyup = function (e) {
var code = (e.code || e.key).toLowerCase();
switch (code) {
case 'keyq':
case 'q':
case 'keyw':
case 'w':
case 'arrowup':
case 'up':
case 'keye':
case 'e':
case 'keya':
case 'a':
case 'arrowleft':
case 'left':
case 'keys':
case 's':
case 'arrowdown':
case 'down':
case 'keyd':
case 'd':
case 'arrowright':
case 'right':
CellUtil.clearLoopEventTime();
break;
case 'space':
case 'spacebar':
CellUtil.clearLoopEventTime();
CellUtil.pauseOrRestore();
break;
}
};
return false;
}
})();
(function () {
function click(dom, downFunc, upFunc) {
var el = dom.setCapture ? dom : document;
dom.onmousedown = function (ev) {
dom.focus();
var oEvent = ev || window.event;
downFunc(oEvent);
el.onmouseup = function (ev) {
var oEvent = ev || window.event;
if(oEvent.stopPropagation) {
oEvent.stopPropagation();
} else {
oEvent.cancelBubble = true;
}
upFunc(oEvent);
el.onmousemove = null; el.onmouseup = null; if(dom.releaseCapture) {dom.releaseCapture();}
};
if(dom.setCapture) {dom.setCapture();}
return false;
};
}
click(leftTurn, function (e) {
leftTurn.classList.add('down');
CellUtil.keyDown(4);
}, function (e) {
leftTurn.classList.remove('down');
CellUtil.clearLoopEventTime();
});
click(rightTurn, function (e) {
rightTurn.classList.add('down');
CellUtil.keyDown(5);
}, function (e) {
rightTurn.classList.remove('down');
CellUtil.clearLoopEventTime();
});
click(leftMove, function (e) {
leftMove.classList.add('down');
CellUtil.keyDown(1);
}, function (e) {
leftMove.classList.remove('down');
CellUtil.clearLoopEventTime();
});
click(bottomMove, function (e) {
bottomMove.classList.add('down');
CellUtil.keyDown(3);
}, function (e) {
bottomMove.classList.remove('down');
CellUtil.clearLoopEventTime();
});
click(rightMove, function (e) {
rightMove.classList.add('down');
CellUtil.keyDown(2);
}, function (e) {
rightMove.classList.remove('down');
CellUtil.clearLoopEventTime();
});
click(startNormalDom, function (e) {
startNormalDom.classList.add('down');
}, function (e) {
startNormalDom.classList.remove('down');
CellUtil.initNormal();
});
click(startRandomDom, function (e) {
startRandomDom.classList.add('down');
}, function (e) {
startRandomDom.classList.remove('down');
CellUtil.initRandom();
});
click(pauseRestoreDom, function (e) {
pauseRestoreDom.classList.add('down');
}, function (e) {
pauseRestoreDom.classList.remove('down');
CellUtil.clearLoopEventTime();
CellUtil.pauseOrRestore();
});
})();
})(window, document);