javascript实现俄罗斯方块

作者分享了自己首次独立完成的俄罗斯方块小游戏的开发经历,包括使用JavaScript进行编程实现,涉及游戏规则、图形绘制、键盘事件处理及游戏逻辑等核心部分。通过实践提升编程技能,强调了学习与练习的重要性。
摘要由CSDN通过智能技术生成

以前一直想写俄罗斯方块,连连看,坦克大战等经典的小游戏,不过本人太浮躁,每次写一半遇到问题就放弃了。

这次是自己第一次坚持写完了这个俄罗斯方块。

对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);							
			}		
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值