以前一直想写俄罗斯方块,连连看,坦克大战等经典的小游戏,不过本人太浮躁,每次写一半遇到问题就放弃了。
这次是自己第一次坚持写完了这个俄罗斯方块。
对javascript不是很熟,所以一些编程的格式,用法什么的不太规范,还需继续努力,加油,学习学习在学习,练习练习在练习。
<html>
<head>
</head>
<body οnkeydοwn="keydown(event)">
<canvas id="tetrisCanvas" width="250" height="500" style="border-style:solid;">
您的浏览器不支持canvas标签
</canvas>
<input type="button" value="开始游戏" onClick="startGame()">
score:<input type="text" id="score"></input>
level:<input type="text" id="level"></input>
<p id = "log"></p>
<script type="text/javascript" src="TetrisV2_1.js"></script>
</body>
</html>
var gameCanvas = document.getElementById("tetrisCanvas"); // 得到画布对象
var cxt = gameCanvas.getContext("2d"); // 得到对象的context,这里我理解为得到一支没有颜色的笔cxt
var GAME_WIDTH = 10; // 游戏的宽度,可以放10个方块
var GAME_HEIGHT = 20; // 游戏的高度,可以放20个方块
var BOX_SIZE = 25; // 每个方块的大小
var ADJUST_LOCATION = 3; // 调整新图形放入时的位置
var score = 0; // 游戏得分
var level = 0; // 游戏等级
var showLevel = document.getElementById("level"); // 显示等级
var speed = 1000; // 游戏速度 1000表示 1000毫秒也就是1秒移动一次
var timer; // 游戏定时器,周期性调用方法
var currentShapeNumber = 0; // 游戏中当前可移动的形状号码
currentShapeRotated = false; // 图形是否旋转过
var nextShapeNumber = 0; // 下一个即将出现的形状号码
var shapeCanMove = false; // 游戏是否有可移动图形
var rotatePointX = 0; // 图形当前旋转中心X坐标
var rotatePointY = 0; // 图形当前旋转中心Y坐标
var log = document.getElementById("log"); // log
var scoreHandle = document.getElementById("score"); // 显示分数
var isGameOver = false; // 标记游戏是否结束
/*
用一个2维数组来管理整个游戏
0 - 没有方块
1 - 可移动方块
大于1 - 不可移动的方块
*/
var gameArray = new Array;
// O形状
var O_SHAPE = [[0,0,0,0],
[1,1,0,0],
[1,1,0,0],
[0,0,0,0]];
// L形状
var L_SHAPE = [[0,1,0,0],
[0,1,0,0],
[1,1,0,0],
[0,0,0,0]];
L_SHAPE.ROTATE_POINT_X = 1;
L_SHAPE.ROTATE_POINT_Y = 1;
// J形状
var J_SHAPE = [[1,1,0,0],
[0,1,0,0],
[0,1,0,0],
[0,0,0,0]];
J_SHAPE.ROTATE_POINT_X = 1;
J_SHAPE.ROTATE_POINT_Y = 1;
// S形状
var S_SHAPE = [[0,1,0,0],
[1,1,0,0],
[1,0,0,0],
[0,0,0,0]];
S_SHAPE.ROTATE_POINT_X = 1;
S_SHAPE.ROTATE_POINT_Y = 1;
// Z形状
var Z_SHAPE = [[1,0,0,0],
[1,1,0,0],
[0,1,0,0],
[0,0,0,0]];
Z_SHAPE.ROTATE_POINT_X = 1;
Z_SHAPE.ROTATE_POINT_Y = 1;
// T形状
var T_SHAPE = [[1,0,0,0],
[1,1,0,0],
[1,0,0,0],
[0,0,0,0]];
T_SHAPE.ROTATE_POINT_X = 1;
T_SHAPE.ROTATE_POINT_Y = 0;
// I形状
var I_SHAPE = [[1,0,0,0],
[1,0,0,0],
[1,0,0,0],
[1,0,0,0]];
I_SHAPE.ROTATE_POINT_X = 1;
I_SHAPE.ROTATE_POINT_Y = 0;
// 存放所有的图形,数组中的位置可以用来标示其颜色位置
var shapes = [O_SHAPE, L_SHAPE, J_SHAPE, S_SHAPE, Z_SHAPE, T_SHAPE, I_SHAPE];
/*
存放颜色信息,在数组中的位置跟在图形数组中的位置对应
#FF0000 红色
#FF8800 橙色
#FFFF00 黄色
#00FF99 绿色
#00BBFF 蓝色
#9900FF 紫色
#FF00FF 淡紫
*/
var COLORS = ["#FF0000", "#FF8800", "#FFFF00", "#00FF99", "#00BBFF", "#9900FF", "#FF00FF"];
// 每种形状代表的颜色
O_SHAPE.COLOR = COLORS[0];
L_SHAPE.COLOR = COLORS[1];
J_SHAPE.COLOR = COLORS[2];
S_SHAPE.COLOR = COLORS[3];
Z_SHAPE.COLOR = COLORS[4];
T_SHAPE.COLOR = COLORS[5];
I_SHAPE.COLOR = COLORS[6];
/*
绑定键盘按下时事件
keyCode:38 ↑ - 变形
keyCode:37 ← - 向左移动
keyCode:39 → - 向右移动
keyCode:40 ↓ - 快速下降
*/
function keydown(evt) {
var evt = evt || event;
if(evt.keyCode == 37) {
moveLeft();
}
if(evt.keyCode == 38) {
rotate();
}
if(evt.keyCode == 39) {
moveRight();
}
if(evt.keyCode == 40) {
moveDown();
}
}
// 游戏初始化
function init() {
/*
给游戏数组值都设为0
*/
gameArray = new Array(GAME_WIDTH);
for(var x = 0; x < GAME_WIDTH; x++) {
gameArray[x] = new Array(GAME_HEIGHT);
for(var y = 0; y < GAME_HEIGHT; y++) {
gameArray[x][y] = 0;
}
}
score = 0; // 开始分数为0
scoreHandle.value = score; //显示分数
level = 1; // 游戏开始等级为1
showLevel.value = level;
speed = 1000; // 开始游戏速度为1秒运行一次
isGameOver = false; // 游戏没有结束
currentShapeNumber = randomNewShapeNumber();
putShape();
drawGame();
nextShapeNumber = randomNewShapeNumber();
}
// 开始游戏
function startGame() {
init(); // 执行初始化方法
setTimeout("gameTimer()", speed/level);
}
function gameTimer() {
if(isGameOver) {
clearTimeout(timer);
alert("Game Over");
return;
}
if(shapeCanMove) {
moveDown();
}else {
removeFullLines();
currentShapeNumber = nextShapeNumber;
putShape();
drawGame();
nextShapeNumber = randomNewShapeNumber();
}
timer = setTimeout("gameTimer()", speed/level);
}
// 产生一个随机图形,并返回在shapes里的这个图形号码
function randomNewShapeNumber() {
/*
随机产生一个0到shapes.length的数
Math.random() // 产生一个0到1的随机数
Math.floor(number) // number的值向下舍入,比如0 - 0.9都表示为0
*/
shapeNumber = Math.floor(Math.random()*shapes.length);
return shapeNumber;
}
// 把产生的图形放入游戏中
function putShape() {
// log.innerHTML += currentShapeNumber;
var currentShape = shapes[currentShapeNumber];
rotatePointX = currentShape.ROTATE_POINT_X + ADJUST_LOCATION; // 图形在游戏中的中心点X坐标
rotatePointY = currentShape.ROTATE_POINT_Y; // 图形在游戏中的中心点Y坐标
for(var x = 0; x < currentShape.length; x++) {
for(var y = 0; y < currentShape[x].length; y++) {
if(currentShape[x][y] == 1) {
if(gameArray[x + ADJUST_LOCATION][y] == 2){
isGameOver = true;
}
gameArray[x + ADJUST_LOCATION][y] = 1; //放入gameArray里并调整其位置
}
}
}
shapeCanMove = true; // 新加入一个形状,可移动
}
// 下移
function moveDown() {
var action = "down";
if(ifCanMove(action)) {
for(var y = GAME_HEIGHT - 1; y >= 0; y--) {
for(var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) { // 图形从下面开始每个方块依次下移
gameArray[x][y] = 0;
gameArray[x][y + 1] = 1;
}
}
}
rotatePointY++; //旋转点也下移一格
} else {
// 如果不能下移,则设置图形所有值为2,表示此图形不能再移动
for(var y = GAME_HEIGHT - 1; y >= 0; y--) {
for(var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) {
gameArray[x][y] = 2;
}
}
}
shapeCanMove = false; // 没有可以移动的图形了
}
drawGame();
}
// 左移
function moveLeft() {
var action = "left";
if(ifCanMove(action)) {
for(var y = GAME_HEIGHT - 1; y >= 0; y--) {
for(var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) { // 图形从左边开始每个方块依次左移
gameArray[x][y] = 0;
gameArray[x - 1][y] = 1;
}
}
}
rotatePointX--; //旋转点也左移一格
}
drawGame();
}
// 右移
function moveRight() {
var action = "right";
if(ifCanMove(action)) {
for(var y = GAME_HEIGHT - 1; y >= 0; y--) {
for(var x = GAME_WIDTH - 1; x >= 0; x--) {
if(gameArray[x][y] == 1) { // 图形从右边开始每个方块依次右移
gameArray[x][y] = 0;
gameArray[x + 1][y] = 1;
}
}
}
rotatePointX++; //旋转点也左移一格
}
drawGame();
}
// 是否能移动,action表示移动方向
function ifCanMove(action) {
switch(action) {
case "down":
for(var x = 0; x < GAME_WIDTH; x++) {
for(var y = 0; y < GAME_HEIGHT; y++) {
if(gameArray[x][y] == 1) {
if( y == (GAME_HEIGHT -1)) { // 如果图形到底部了,返回false不能移动
return false;
} else if (gameArray[x][y + 1] == 2){ // 图形每一个方块下面那块如果有其它已有方块,返回false不能移动
return false;
}
}
}
}
return true;
case "left":
for(var x = 0; x < GAME_WIDTH; x++) {
for(var y = 0; y < GAME_HEIGHT; y++) {
if(gameArray[x][y] == 1) { // 如果图形到最左边了,返回false不能移动
if( x == 0) {
return false;
} else if (gameArray[x - 1][y] == 2){ // 图形每一个方块左边那块如果有其它已有方块,返回false不能移动
return false;
}
}
}
}
return true;
case "right":
for(var x = 0; x < GAME_WIDTH; x++) {
for(var y = 0; y < GAME_HEIGHT; y++) {
if(gameArray[x][y] == 1) { // 如果图形到最右边了,返回false不能移动
if( x == (GAME_WIDTH -1)) {
return false;
} else if (gameArray[x + 1][y] == 2){ // 图形每一个方块右边那块如果有其它已有方块,返回false不能移动
return false;
}
}
}
}
return true;
default:
alert("wrong action");
}
}
/*
变形
变形公式:
顺时针
X = Y - deltY + deltX;
y = - (X - deltX) + deltY;
逆时针
X = -(Y - deltY) + deltX;
y = X - deltX + deltY;
*/
function rotate() {
var tempShape = [[0,0],[0,0],[0,0],[0,0]];
var tempCount = 0;
for ( var y = 0; y < GAME_HEIGHT; y++) {
for( var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) {
tempShape[tempCount][0] = x;
tempShape[tempCount][1] = y;
tempCount++;
}
}
}
if(currentShapeNumber == 0) {
}
if(currentShapeNumber == 1 || currentShapeNumber == 2 || currentShapeNumber == 5) {
if(ifCanRotate(tempShape)) {
for ( var y = 0; y < GAME_HEIGHT; y++) {
for( var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) {
gameArray[x][y] = 0;
}
}
}
for ( var i = 0; i < tempShape.length; i++) {
var tempX = -(tempShape[i][1] - rotatePointY) + rotatePointX;
var tempY = (tempShape[i][0] - rotatePointX) +rotatePointY;
gameArray[tempX][tempY] = 1;
}
}
}
if(currentShapeNumber == 3 || currentShapeNumber == 4 || currentShapeNumber == 6) {
if(ifCanRotate(tempShape)) {
for ( var y = 0; y < GAME_HEIGHT; y++) {
for( var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 1) {
gameArray[x][y] = 0;
}
}
}
if(currentShapeRotated) {
for ( var i = 0; i < tempShape.length; i++) {
var tempX = (tempShape[i][1] - rotatePointY) + rotatePointX;
var tempY = -(tempShape[i][0] - rotatePointX) +rotatePointY;
gameArray[tempX][tempY] = 1;
}
}else{
for ( var i = 0; i < tempShape.length; i++) {
var tempX = -(tempShape[i][1] - rotatePointY) + rotatePointX;
var tempY = (tempShape[i][0] - rotatePointX) +rotatePointY;
gameArray[tempX][tempY] = 1;
}
}
if(currentShapeRotated) {
currentShapeRotated = false;
}else {
currentShapeRotated = true;
}
}
}
drawGame();
}
// 是否能旋转
function ifCanRotate(rotatedShape) {
if(currentShapeNumber == 1 || currentShapeNumber == 2 || currentShapeNumber == 5) {
for(var i = 0; i < rotatedShape.length; i++) {
var tempX = rotatedShape[i][1] - rotatePointY + rotatePointX;
var tempY = -(rotatedShape[i][0] - rotatePointX) + rotatePointY;
if(tempX < 0 || tempX >= GAME_WIDTH) {
return false;
}else if(gameArray[tempX][tempY] == 2 ) {
return false;
}else if(tempY < 0 || tempY >= GAME_HEIGHT) {
return false;
}
}
return true;
}
if(currentShapeNumber == 3 || currentShapeNumber == 4 || currentShapeNumber == 6) {
if(currentShapeRotated) {
for(var i = 0; i < rotatedShape.length; i++) {
var tempX = (rotatedShape[i][1] - rotatePointY) + rotatePointX;
var tempY = -(rotatedShape[i][0] - rotatePointX) + rotatePointY;
if(tempX < 0 || tempX >= GAME_WIDTH) {
return false;
}else if(gameArray[tempX][tempY] == 2 ) {
return false;
}else if(tempY < 0 || tempY >= GAME_HEIGHT) {
return false;
}
}
return true;
}else {
for(var i = 0; i < rotatedShape.length; i++) {
var tempX = -(rotatedShape[i][1] - rotatePointY) + rotatePointX;
var tempY = (rotatedShape[i][0] - rotatePointX) + rotatePointY;
if(tempX < 0 || tempX >= GAME_WIDTH) {
return false;
}else if(gameArray[tempX][tempY] == 2 ) {
return false;
}else if(tempY < 0 || tempY >= GAME_HEIGHT) {
return false;
}
}
return true;
}
}
}
// 删除所有满的行
function removeFullLines() {
var removeLines = 0;
for( var y = 0; y < GAME_HEIGHT; y++) {
for ( var x = 0; x < GAME_WIDTH; x++) {
if(gameArray[x][y] == 0) {
break;
}else if( x == (GAME_WIDTH - 1)) {
removeLines++;
for ( var ry = y; ry >= 0 ; ry--) {
for ( var x = 0; x < gameArray.length; x++) {
if(ry == 0) {
gameArray[x][ry] = 0; // 第一行都设为零
} else {
gameArray[x][ry] = gameArray[x][ry-1]; // 所有行下移
}
}
}
}
}
}
switch(removeLines) {
case 1:
score += 100;
scoreHandle.value = score;
break;
case 2:
score += 200;
scoreHandle.value = score;
break;
case 3:
score += 400;
scoreHandle.value = score;
break;
case 4:
score += 800;
scoreHandle.value = score;
break;
}
if(score >= 200 && score < 500) {
level = 2;
showLevel.value = level;
}else if(score >= 500 && score < 1000) {
level = 3;
showLevel.value = level;
}else if(score >= 1000 && score < 1600) {
level = 4;
showLevel.value = level;
}else if(score >= 1600 && score < 2200) {
level = 5;
showLevel.value = level;
}else if(score >= 2200 && score < 2900) {
level = 6;
showLevel.value = level;
}else if(score >= 2900 && score < 3600) {
level = 7;
showLevel.value = level;
}else if(score >= 3600 && score < 4400) {
level = 8;
showLevel.value = level;
}else if(score >= 4400 && score < 5000) {
level = 9;
showLevel.value = level;
}else if(score >= 5000 && score < 5700) {
level = 10;
showLevel.value = level;
}else if(score >= 5700 && score < 6400) {
level = 11;
showLevel.value = level;
}else if(score >= 6400 && score < 7200) {
level = 12;
showLevel.value = level;
}else if(score >= 7200 && score < 8000) {
level = 13;
showLevel.value = level;
}else if(score >= 8000 && score < 8800) {
level = 14;
showLevel.value = level;
}
}
// 有游戏数组画到画布上
function drawGame() {
for( var x = 0; x < GAME_WIDTH; x++) {
for ( var y = 0; y < GAME_HEIGHT; y++) {
// 值为零的清除该方块
if(gameArray[x][y] == 0) {
cxt.clearRect(x * BOX_SIZE, y * BOX_SIZE, BOX_SIZE, BOX_SIZE);
}
// 值大于零时画出该方块
if(gameArray[x][y] >= 1) {
// cxt.fillStyle = shapes[currentShape].COLOR;
cxt.fillStyle = "FF8800";
cxt.fillRect(x * BOX_SIZE, y * BOX_SIZE, BOX_SIZE, BOX_SIZE);
}
}
}
}