本来写了上篇的,可是写得不太好,而且方块的左右移动那里还有bug,索性把上篇删了,只用一篇来说。
效果图
不要用IE浏览器打开,不然会变成......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>俄罗斯方块</title>
</head>
<style type="text/css">
body {
font-family: monospace;
}
.center {
position: absolute;
left: 50%;
width: 800px;
margin-left: -200px;
}
</style>
<body>
<h1 id="scene" class="center" style="line-height:100%"></h1>
<div style="float:left">
<h2 id="msg">score:0</h2>
<h2 id="nextBlocks" style="line-height:100%"></h2>
<button id="btn" type="button">开始游戏</button>
</div>
<script>
var KEY_UP = 38; //上箭头
var KEY_DOWN = 40; //下箭头
var KEY_LEFT = 37; //左箭头
var KEY_RIGHT = 39; //右箭头
var KEY_SPACE = 32; //空格键
var BLOCK_SOLID = "█"; //实心方块
var BLOCK_HOLLOW = "□"; //空心方块
var BLOCK_TYPE_NUM = 7; //方块的种类
var width = 10; //宽
var height = 20; //高
var scene = new Array(); //场景
var sleepTime = 400; //延时时间
var blocks; //方块
var score = 0; //分数
var highestScore = 0; //最高分
var nextBlocksType; //下一个方块的种类
var isGameOver = true; //游戏是否已经结束
var interval; //定时器
document.onkeydown = onKeyDown;
//按键监听
function onKeyDown(e) {
if (isGameOver) return;
switch (e.which) {
case KEY_LEFT:
//向左移动
moveBlocks(-1);
break;
case KEY_RIGHT:
//向右移动
moveBlocks(1);
break;
case KEY_DOWN:
//跳到底部
skipToBottom();
break;
case KEY_UP:
//旋转方块
rotateBlocks();
break;
case KEY_SPACE:
//加速移动
drop();
break;
}
printScene();
}
//按钮
function onBtnClick() {
isGameOver = false;
document.getElementById("btn").disabled = true;
//打开方块下落的定时器
interval = window.setInterval(function () { drapBlock() }, sleepTime);
getNextBlocksType();
produceBlocks();
printMsg("score:0");
init();
}
//初始化
function init() {
initScene();
drawFrame();
printScene();
}
//产生方块
function produceBlocks() {
blocks = getBlocksByType(nextBlocksType);
getNextBlocksType();
printNextBlocks();
}
//随机获取下一次的方块
function getNextBlocksType() {
do {
nextBlocksType = Math.round(Math.random() * BLOCK_TYPE_NUM);
} while (nextBlocksType == 0);
nextBlocksType--;
}
//获取指定类型的方块
function getBlocksByType(type) {
var tBlocks = new Object();
tBlocks.x = new Array();
tBlocks.y = new Array();
switch (type) {
case 0: //T
for (var i = 0; i < 3; i++) {
tBlocks.x[i] = width / 2 + i - 1;
tBlocks.y[i] = -1;
}
tBlocks.x[3] = width / 2;
tBlocks.y[3] = -2;
tBlocks.center = 1;
break;
case 1: //I
for (var i = 0; i <= 3; i++) {
tBlocks.x[i] = width / 2 - i + 1;
tBlocks.y[i] = -1;
}
tBlocks.center = 1;
break;
case 2: //O
for (var i = 0; i < 4; i++) {
tBlocks.x[i] = width / 2 + i % 2 - 1;
tBlocks.y[i] = -2 + parseInt(i / 2);
}
tBlocks.center = -1;
break;
case 3: //L
tBlocks.x[0] = width / 2 - 1;
tBlocks.y[0] = -2;
for (var i = 1; i < 4; i++) {
tBlocks.x[i] = width / 2 + i - 2;
tBlocks.y[i] = -1;
}
tBlocks.center = 2;
break;
case 4: //J
tBlocks.x[0] = width / 2 + 1;
tBlocks.y[0] = -2;
for (var i = 1; i < 4; i++) {
tBlocks.x[i] = width / 2 + i - 2;
tBlocks.y[i] = -1;
}
tBlocks.center = 2;
break;
case 5: //Z
tBlocks.x[0] = width / 2 - 1;
tBlocks.y[0] = -2;
tBlocks.x[1] = width / 2;
tBlocks.y[1] = -2;
tBlocks.x[2] = width / 2;
tBlocks.y[2] = -1;
tBlocks.x[3] = width / 2 + 1;
tBlocks.y[3] = -1;
tBlocks.center = 1;
break;
case 6: //S
tBlocks.x[0] = width / 2;
tBlocks.y[0] = -2;
tBlocks.x[1] = width / 2 + 1;
tBlocks.y[1] = -2;
tBlocks.x[2] = width / 2 - 1;
tBlocks.y[2] = -1;
tBlocks.x[3] = width / 2;
tBlocks.y[3] = -1;
tBlocks.center = 0;
break;
}
return tBlocks;
}
//初始化屏幕数组
function initScene() {
for (var i = 0; i < height + 2; i++) {
scene[i] = new Array();
for (var j = 0; j < width + 2; j++) {
scene[i][j] = BLOCK_HOLLOW;
}
}
}
//在指定位置画点
function drawPointAt(x, y) {
drawChAt(x, y, BLOCK_SOLID);
}
//清除指定位置的点
function clearPointAt(x, y) {
drawChAt(x, y, BLOCK_HOLLOW);
}
//在指定位置是否是实心方块
function isSolidAt(x, y) {
return getChAt(x, y) == BLOCK_SOLID;
}
//在指定位置画字符
function drawChAt(x, y, s) {
scene[y + 1][x + 1] = s;
}
//获取指定位置的字符
function getChAt(x, y) {
return scene[y + 1][x + 1];
}
//画边框
function drawFrame() {
for (var i = 0; i < width; i++) {
drawChAt(i, -1, "─");
drawChAt(i, height, "─");
}
for (var i = 0; i < height; i++) {
drawChAt(-1, i, "│");
drawChAt(width, i, "│");
}
drawChAt(-1, height, "└");
drawChAt(width, height, "┘");
drawChAt(-1, -1, "┌");
drawChAt(width, -1, "┐");
}
//绘制场景
function printScene() {
var str = "";
for (var i = 0; i < height + 2; i++) {
for (var j = 0; j < width + 2; j++) {
if (i > 0) {
var k;
if (blocks != undefined) {
for (k = 0; k < blocks.x.length; k++) {
if (i == blocks.y[k] + 1 && j == blocks.x[k] + 1) break;
}
}
if (blocks != undefined && k != blocks.x.length) {
str += BLOCK_SOLID;
} else {
str += scene[i][j];
}
} else {
str += scene[i][j];
}
}
str += "<br/>";
}
document.getElementById("scene").innerHTML = str;
}
//方块下落
function drapBlock() {
if (isBump(0, 1)) fixBlocks();
drop();
}
//左右移动方块,-1向左移,1向右移
function moveBlocks(dir) {
if (!isBump(dir, 0))
move(dir);
printScene();
}
//移动方块
function move(dir) {
for (var i = 0, count = blocks.x.length; i < count; i++) {
blocks.x[i] += dir;
}
}
//方块跳到底部
function skipToBottom() {
while (drop()) { }
fixBlocks();
}
//方块下落
function drop() {
if (isBump(0, 1)) return false;
for (var i = 0, count = blocks.x.length; i < count; i++) {
blocks.y[i]++;
}
printScene();
return true;
}
//旋转方块
function rotateBlocks() {
if (blocks.center == -1) return; //不能旋转的方块
rotate(1);
//检测到碰撞,返回原来的位置
if (isBump(0, 0)) rotate(-1); //反向旋转,即返回原来的位置
printScene();
}
//旋转, 1顺时针,-1逆时针
function rotate(dir) {
var cX = blocks.x[blocks.center];
var cY = blocks.y[blocks.center];
for (var i = 0, count = blocks.x.length; i < count; i++) {
var xt = blocks.x[i];
if (dir == 1) {
blocks.x[i] = cX + cY - blocks.y[i];
blocks.y[i] = xt - cX + cY;
} else {
blocks.x[i] = cX - cY + blocks.y[i];
blocks.y[i] = cX + cY - xt;
}
}
}
//固定方块
function fixBlocks() {
for (var i = 0, count = blocks.x.length; i < count; i++) {
if (blocks.y[i] < 0) { //游戏结束
gameOver();
return;
}
drawPointAt(blocks.x[i], blocks.y[i]);
}
produceBlocks();
elimLine();
}
//消除方块检测,有填满一行的就消去
function elimLine() {
for (var y = 0; y < height; y++) {
var x;
for (x = 0; x < width; x++) {
if (getChAt(x, y) != BLOCK_SOLID) break;
}
if (x == width) {
clearLine(y);
score++;
}
}
printMsg("score:" + score);
}
//消除一行
function clearLine(y) {
for (; y > 1; y--) {
for (var x = 0; x < width; x++) {
drawChAt(x, y, getChAt(x, y - 1));
drawChAt(x, y - 1, BLOCK_HOLLOW);
}
}
}
//输出信息
function printMsg(s) {
document.getElementById("msg").innerHTML = s;
}
//显示下一个方块
function printNextBlocks() {
var tBlocks = getBlocksByType(nextBlocksType);
var str = "";
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var k;
var count = tBlocks.x.length;
for (k = 0; k < count; k++) {
if (i == tBlocks.y[k] + 3 && j == tBlocks.x[k] - width / 2 + 2) break;
}
if (k == count) str += " ";
else str += BLOCK_SOLID;
}
str += "<br/>";
}
document.getElementById("nextBlocks").innerHTML = str;
}
//是否有碰撞, dx和dy为偏移量
function isBump(dx, dy) {
var i;
var count = blocks.x.length;
for (i = 0; i < count; i++) {
if (blocks.x[i] + dx < 0 || blocks.x[i] + dx >= width ||
blocks.y[i] + dy >= height ||
isSolidAt(blocks.x[i] + dx, blocks.y[i] + dy))
return true;
}
return false;
}
//游戏结束
function gameOver() {
if (highestScore < score) highestScore = score;
printMsg("score:" + score + "<br/>highestScore:" + highestScore + "<br/>GameOver");
isGameOver = true;
score = 0;
document.getElementById("btn").disabled = false;
window.clearInterval(interval);
}
document.getElementById("btn").onclick = onBtnClick;
window.onload = () => init();
</script>
</body>
</html>
方块的种类:
方块的旋转
流程图