js俄罗斯方块

本文介绍了一个基于HTML5 canvas的简易俄罗斯方块游戏的实现过程,包括使用二维数组表示地图,通过定时器控制方块的下落和移动,以及基本的得分计算逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个简单的俄罗斯方块游戏

基本思路:

用一个二维数组来表示地图,把方块的移动看成在二维数组上的移动,0表示空位,1表示已经落定的方块,2表示正在下落的方块,3表示边界

游戏主要用HTML5的canvas绘图来完成,按照一定的时间间隔在数组值为1或2的地方绘制

游戏在chrom下开发测试,暂时存在一些缺陷,效果见 http://snailanger.free3v.net/russian.html

代码如下

html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>russian</title>
		<meta name="description" content="">
		<meta name="author" content="Thinkpad">
		<link rel="stylesheet" type="text/css" href="russian.css" /> 
	</head>
	<body>
	    <div class="backdiv">
			<canvas id="mcns" width="200" height="400" class="canvas"></canvas>
			<canvas id="icns" width="100" height="100" class="info_canvas"></canvas>
			<span id="score" class="info_span">0</span>
		</div>
	</body>
	<script type="text/javascript" src="russian.js"></script>
</html>
css

.backdiv{
	width: 350px;
	height: 410px;
	margin: 0 auto;
}
.canvas{
	border: 1px solid gray;
    float: right;
}
.info_canvas{
	border: 1px solid gray;
    float: left;
    margin-bottom:70px;
}
.info_span{
	float: left;
	margin-left:30px;
	font-size: 33px
}
js

var x = 3; //全局移动坐标
var y = 4;
var start_x = 3;//起始行
var start_y = 4;
var old_x; //上一步坐标
var old_y;
var map; //0空,1已经落下的块,2正在下落的块,3边界
var row = 24; // 全局数组大小
var column = 12;
var size = 18; //方块大小
var fix_xy = 20; // xy轴偏移量
var fix_x = 19; //xy方向修正
var fix_y = 59;
var canvas_width = 200; //画布大小
var canvas_height = 400;
var canvas;  //画布对象
var ctx = null; //画笔
var ctxInfo = null;
var paint_color = "red"; //画笔颜色
var diamonds = null; //当前方块
var nextDiamonds = null; //下一个方块
var count = 0; //统计消行
var clear_row = null; //保存要消的行
var score = 100; //单位得分
var ratio = 1; //分数系数
var total_score = 0; //当前消行总分
var html_score = 0; //总分
var downIndex = 0; //开始消行序号
var run = null; //游戏控制
var speed = 600; //速度
var total_count = 0; //消行总次数
//基本图形分为坐标,颜色,变形指向,最大列,第一个坐标为最下方最右边的块
var baseDiamonds = [{
	diamonds:[[0,3],[0,2],[0,1],[0,0],"red",1,3] // ——
},
{
	diamonds:[[0,0],[-1,0],[-2,0],[-3,0],"red",0,0] // |
},
{
	diamonds:[[0,1],[0,0],[-1,1],[-1,0],"black",2,1] // 口
},
{
	diamonds:[[0,2],[0,1],[0,0],[-1,1],"yellow",4,2] // ⊥
},
{
	diamonds:[[0,0],[-1,1],[-1,0],[-2,0],"yellow",5,1] // |-
},
{
	diamonds:[[0,1],[-1,2],[-1,1],[-1,0],"yellow",6,2] // T
},
{
	diamonds:[[0,1],[-1,1],[-1,0],[-2,1],"yellow",3,1] // -|
},
{
	diamonds:[[0,0],[-1,0],[-2,0],[-2,1],"green",8,1] // 『
},
{
	diamonds:[[0,2],[-1,2],[-1,1],[-1,0],"green",9,2] // 『右转1
},
{
	diamonds:[[0,1],[0,0],[-1,1],[-2,1],"green",10,1] // 『右转2
},
{
	diamonds:[[0,2],[0,1],[0,0],[-1,0],"green",7,2] // 『右转3
},
{
	diamonds:[[0,1],[-1,1],[-2,1],[-2,0],"blue",12,1] // 『反向那个
},
{
	diamonds:[[0,2],[0,1],[0,0],[-1,2],"blue",13,2] // 『反向那个右转1
},
{
	diamonds:[[0,1],[0,0],[-1,0],[-2,0],"blue",14,1] // 『反向那个右转2
},
{
	diamonds:[[0,0],[-1,2],[-1,1],[-1,0],"blue",11,2] // 『反向那个右转3
},
{
	diamonds:[[0,2],[0,1],[-1,1],[-1,0],"orange",16,2] // Z
},
{
	diamonds:[[0,0],[-1,0],[-1,1],[-2,1],"orange",15,1] // Z右转1
},
{
	diamonds:[[0,1],[0,0],[-1,1],[-1,2],"gray",18,2] // Z反向那个
},
{
	diamonds:[[0,1],[-1,1],[-1,0],[-2,0],"gray",17,1] // Z反向那个右转1
}
];
//初始化游戏参数
function init(){
	canvas = document.getElementById("mcns");  
    ctx = canvas.getContext("2d"); 
    ctx.fillStyle = paint_color; 
    canvasInfo = document.getElementById("icns");  
    ctxInfo = canvasInfo.getContext("2d"); 
    ctxInfo.fillStyle = "blue";
    map = new Array(); //初始化地图数组
	for(var i=0;i<row;i++){
		map.push(new Array());
		for(var j=0;j<column;j++){
			if(i==row-1 || j==0 || j==column-1){
				map[i].push(3);
			}else{
				map[i].push(0);
			}
		}
	}
	x = start_x;
	y = start_y;
	html_score = document.getElementById("score");
}
//绘制当前方块
function paint(){
	ctx.clearRect(0,0,canvas_width,canvas_height); //清空画布
	// paintGrid();
    resetMap(y,x,2);
    for(var i=start_x;i<row;i++){ //在当前位置为1或2的地方绘制
    	for(var j=0;j<column;j++){
    		if(map[i][j] == 1 || map[i][j] == 2){
    			ctx.fillRect(fix_xy*j-fix_x,fix_xy*i-fix_y,size,size);
    		}
    	}
    }
}
//绘制下一个方块
function paintInfo(){
	ctxInfo.clearRect(0,0,100,100);
	for(var i=0;i<4;i++){
		ctxInfo.fillRect(fix_xy*nextDiamonds[i][1]+21,fix_xy*nextDiamonds[i][0]+61,size,size);
	}
}
//绘制背景表格
function paintGrid(){
	for(var i=1;i<20;i++){
		ctx.moveTo(0,i*fix_xy);
	    ctx.lineTo(canvas_width,i*fix_xy);
	    ctx.stroke();
	}
	for(var i=1;i<10;i++){
		ctx.moveTo(i*fix_xy,0);
	    ctx.lineTo(i*fix_xy,canvas_height);
	    ctx.stroke();
	}
}
//给map赋值
function resetMap(r,c,val){
	for(var i=0;i<4;i++){
    	map[c+diamonds[i][0]][r+diamonds[i][1]] = val;
    }
}
//方块下落
function down(){
	old_x = x; //保存当前位置
	old_y = y;
	if(!isMove(1,0)){ //如果下一个位置有块,则当前下落结束
		resetMap(y,x,1);
		if(isGameOver()){ //判断游戏是否结束
			gameOver(); //游戏结束
		}else{
		    clearRow(); //消行
		    x = start_x; //将 下落方块坐标还原
            y = start_y;
		    if(createDemonds()){ //生成新的方块
			    paint();
			    paintInfo();
		    }
		}
	}else{ //方块下落一个位置
		resetMap(old_y,old_x,0);
		++x;
	}
	paint();
}
//判断下个位置是否可以移动
function isMove(mx,my){
	for(var i=0;i<4;i++){ //如果下个位置为1或3,即已经落下的方块和边界,则不能移动
		if(map[x+diamonds[i][0]+mx][y+diamonds[i][1]+my] == 1 || map[x+diamonds[i][0]+mx][y+diamonds[i][1]+my] == 3){
			return false;
		}
	}
	return true;
}
//改变方块方向
function changeDirect(val){
	resetMap(y,x,0);
	y += val;
	ctx.clearRect(0,0,canvas_width,canvas_height);
	paint();
}
//消行
function clearRow(){
	clear_row = new Array();
	for(var i=x,len=x-4;i>len;i--){ //从当前位置开始扫描,最多向上扫描三行
		count = 0;
		for(var j=1,len2=column-1;j<len2;j++){
			count += map[i][j];
		}
		if(count == 10){
			clear_row.push(i);
		}
	}
	if(clear_row.length > 0){ //如果有要消的行
		for (var i=0,len=clear_row.length;i<len;i++) { //消行
			for (var j=0,len2=column-1; j<len2; j++) {
				map[clear_row[i]][j] = 0;
			}
		}
		switch(clear_row.length){ //计分系数
			case 1:ratio = 1; break;
			case 2:ratio = 3; break;
			case 3:ratio = 5; break;
			case 4:ratio = 7; break;
		}
		total_score += score * ratio;
		html_score.innerHTML = total_score; 
		total_count += clear_row.length;
		diamondsDown();//消完后下落
		if(total_count%7==0){ //根据消行次数,改变速度
			speed -= 70;
			begin();
		}
	}
}
//消行后块下落
function diamondsDown(){
	clear_row.push(start_x);
	for(var k=0,len=clear_row.length-1;k<len;k++){
		downIndex = clear_row[k]; //获取下落起始行
	    for(var i=downIndex;i>clear_row[k+1];i--){ //逐行扫描,按所消的行数下落
		    for(var j=1,len2=column-1;j<len2;j++){
			   map[i+k][j] = map[i-1][j]; //第一次下移一行,第二次两行,以此类推
			   map[i-1][j] = 0;
		    }
	    }
	}
}
//生成方块
function createDemonds(){
	if(!nextDiamonds){ //如果下一个不存在
		if(!diamonds){
			diamonds = baseDiamonds[parseInt(Math.random()*19)].diamonds;
		}
		nextDiamonds = baseDiamonds[parseInt(Math.random()*19)].diamonds;
	}else{ //若存在,将当前方块换成上次生成的下一个,继续生成下一个
		diamonds = nextDiamonds;
		nextDiamonds = baseDiamonds[parseInt(Math.random()*19)].diamonds;
	}
	return true;
}
//变形
function change(){
	resetMap(y,x,0); //将当前位置清空
	diamonds = baseDiamonds[diamonds[5]].diamonds; //获取当前方块右转后的方块
	if(y+diamonds[6]>10){ //靠右变形修正
		y = 10-diamonds[6];
	}
	paint();
}
//判断游戏是否结束
function isGameOver(){
	for(var j=1;j<column;j++){
		if(map[start_x][j] == 1){
			return true;
		}
	}
	return false;
}
//暂停
function stop(){
	if(run){ //如果当前正在运动,则清掉
		window.clearInterval(run);
		run = null;
	}else{
		run = setInterval("down()",speed);
	}
}
function begin(){
	if(run){ //如果当前正在运动,则清掉
		window.clearInterval(run);
		run = setInterval("down()",speed);
	}
}
//游戏结束
function gameOver(){
	if (confirm('Game Over,是否重新开始?')) {  
        window.clearInterval(run);
	    location.reload(true);  
    }
}
//键盘事件
function keyDown(e){
	var keycode;
	if(e){
		keycode = e.keyCode;
	}else{
		keycode = window.event.keyCode;
	}
	switch(keycode){
		case 37: //左
		    if(isMove(0,-1)){
		    	changeDirect(-1);
		    }
		    break;
		case 38: //上
		    change();
		    break;
		case 39: //右
		    if(isMove(0,1)){
		    	changeDirect(1);
		    }
		    break;
		case 40: //下
		    down(); //加速下落
		    break;
		case 83: //暂停
		    stop();
		    break;
	}
}
document.onkeydown = keyDown; //绑定事件
//开始游戏
init();
if(createDemonds()){
	paint();
	paintInfo();
	run = setInterval("down()",speed);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值