运用JS编写 俄罗斯方块

<html>
<head>
<title>R</title>
<style>
#board tr td{
width: 20px;
height: 20px;
}
</style>
</head>
<script language="javascript">
/**
* JS俄罗斯方块完美注释版 v 1.01
* 从学c语言那一会儿都想写一个俄罗斯方块,可是每次动起手总觉得难度太大.
* 今天终于用了大约4个小时写出来了. 其中在涉及到方块变型的时候还咨询了
* 同学来帮忙;
*
* 个人觉得难点有这么几个:
* 1: 边界检查, 不多说, 想通了就行
* 2: 旋转, 还是数学上的方法, 一个点相对另外一个点旋转90度的问题.
* 4: 让整个程序在点开始之后, 怎么让它一直自动的运行下去. 我以前一直没有做完,
* 主要是因为没有想清楚到底要用一个什么机制让游戏自动运行下去,
* 这个过程可以这么理解:
* 用户点开始->构造一个活动图形, 设置定时器,
* 每次向下移动后, 都检查是否触底, 如果触底了, 则尝试消行,
* 完了之后再构造一个活动图形, 再设置定时器.
*/
//表示页面中的table, 这个table就是将要显示游戏的主面板
var tbl;
//游戏状态 0: 未开始;1 运行; 2 中止;
var status = 0;
//定时器, 定时器内将做moveDown操作
var timer;
//分数
var score = 0;
//board是一个18*10的数组,也和页面的table对应.
//用来标注那些方格已经被占据. 初始时都为0, 如果被占据则为1
var board = new Array(18);
for(var i=0;i<18;i++){
board[i] = new Array(10);
}
for(var i=0;i<18;i++){
for(var j=0; j<10; j++){
board[i][j] = 0;
}
}
//当前活动的方块, 它可以左右下移动, 变型.当它触底后, 将会更新board;
var activeBlock;
//生产方块形状, 有7种基本形状.
function generateBlock(){
activeBlock = null;
activeBlock = new Array(4);
//generate a random int number between 0-6;
var t = (Math.floor(Math.random()*20)+1)%7;
switch(t){
case 0:{
activeBlock[0] = {x:0, y:4};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:0, y:5};
activeBlock[3] = {x:1, y:5};
break;
}
case 1:{
activeBlock[0] = {x:0, y:3};
activeBlock[1] = {x:0, y:4};
activeBlock[2] = {x:0, y:5};
activeBlock[3] = {x:0, y:6};
break;
}
case 2:{
activeBlock[0] = {x:0, y:5};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:1, y:5};
activeBlock[3] = {x:2, y:4};
break;
}
case 3:{
activeBlock[0] = {x:0, y:4};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:1, y:5};
activeBlock[3] = {x:2, y:5};
break;
}
case 4:{
activeBlock[0] = {x:0, y:4};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:1, y:5};
activeBlock[3] = {x:1, y:6};
break;
}
case 5:{
activeBlock[0] = {x:0, y:4};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:2, y:4};
activeBlock[3] = {x:2, y:5};
break;
}
case 6:{
activeBlock[0] = {x:0, y:5};
activeBlock[1] = {x:1, y:4};
activeBlock[2] = {x:1, y:5};
activeBlock[3] = {x:1, y:6};
break;
}
}
//检查刚生产的四个小方格是否可以放在初始化的位置.
for(var i=0; i<4; i++){
if(!isCellValid(activeBlock[i].x, activeBlock[i].y)){
return false;
}
}
return true;
}
//向下移动
function moveDown(){
//检查底边界.
if(checkBottomBorder()){
//没有触底, 则擦除当前图形,
erase();
//更新当前图形坐标
for(var i=0; i<4; i++){
activeBlock[i].x = activeBlock[i].x + 1;
}
//重画当前图形
paint();
}
//触底,
else{
//停止当前的定时器, 也就是停止自动向下移动.
clearInterval(timer);
//更新board数组.
updateBoard();
//消行
var lines = deleteLine();
//如果有消行, 则
if(lines!=0){
//更新分数
score = score + lines*10;
updateScore();
//擦除整个面板
eraseBoard();
//重绘面板
paintBoard();
}
//产生一个新图形并判断是否可以放在最初的位置.
if(!generateBlock()){
alert("Game over!");
status = 2;
return;
}
paint();
//定时器, 每隔一秒执行一次moveDown
timer = setInterval(moveDown,1000)
}
}
//左移动
function moveLeft(){
if(checkLeftBorder()){
erase();
for(var i=0; i<4; i++){
activeBlock[i].y = activeBlock[i].y - 1;
}
paint();
}
}
//右移动
function moveRight(){
if(checkRightBorder()){
erase();
for(var i=0; i<4; i++){
activeBlock[i].y = activeBlock[i].y + 1;
}
paint();
}
}
//旋转, 因为旋转之后可能会有方格覆盖已有的方格.
//先用一个tmpBlock,把activeBlock的内容都拷贝到tmpBlock,
//对tmpBlock尝试旋转, 如果旋转后检测发现没有方格产生冲突,则
//把旋转后的tmpBlock的值给activeBlock.
function rotate(){
var tmpBlock = new Array(4);
for(var i=0; i<4; i++){
tmpBlock[i] = {x:0, y:0};
}
for(var i=0; i<4; i++){
tmpBlock[i].x = activeBlock[i].x;
tmpBlock[i].y = activeBlock[i].y;
}
//先算四个点的中心点,则这四个点围绕中心旋转90度。
var cx = Math.round((tmpBlock[0].x + tmpBlock[1].x + tmpBlock[2].x + tmpBlock[3].x)/4);
var cy = Math.round((tmpBlock[0].y + tmpBlock[1].y + tmpBlock[2].y + tmpBlock[3].y)/4);
//旋转的主要算法. 可以这样分解来理解。
//先假设围绕源点旋转。然后再加上中心点的坐标。
for(var i=0; i<4; i++){
tmpBlock[i].x = cx+cy-activeBlock[i].y;
tmpBlock[i].y = cy-cx+activeBlock[i].x;
}
//检查旋转后方格是否合法.
for(var i=0; i<4; i++){
if(!isCellValid(tmpBlock[i].x,tmpBlock[i].y)){
return;
}
}
//如果合法, 擦除
erase();
//对activeBlock重新赋值.
for(var i=0; i<4; i++){
activeBlock[i].x = tmpBlock[i].x;
activeBlock[i].y = tmpBlock[i].y;
}
//重画.
paint();
}
//检查左边界,尝试着朝左边移动一个,看是否合法.
function checkLeftBorder(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].y==0){
return false;
}
if(!isCellValid(activeBlock[i].x, activeBlock[i].y-1)){
return false;
}
}
return true;
}
//检查右边界,尝试着朝右边移动一个,看是否合法.
function checkRightBorder(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].y==9){
return false;
}
if(!isCellValid(activeBlock[i].x, activeBlock[i].y+1)){
return false;
}
}
return true;
}
//检查底边界,尝试着朝下边移动一个,看是否合法.
function checkBottomBorder(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].x==17){
return false;
}
if(!isCellValid(activeBlock[i].x+1, activeBlock[i].y)){
return false;
}
}
return true;
}
//检查坐标为(x,y)的是否在board种已经存在, 存在说明这个方格不合法.
function isCellValid(x, y){
if(x>17||x<0||y>9||y<0){
return false;
}
if(board[x][y]==1){
return false;
}
return true;
}
//擦除
function erase(){
for(var i=0; i<4; i++){
tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="white";
}
}
//绘活动图形
function paint(){
for(var i=0; i<4; i++){
tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="red";
}
}
//更新board数组
function updateBoard(){
for(var i=0; i<4; i++){
board[activeBlock[i].x][activeBlock[i].y]=1;
}
}
//消行
function deleteLine(){
var lines = 0;
for(var i=0; i<18; i++){
var j=0;
for(; j<10; j++){
if(board[i][j]==0){
break;
}
}
if(j==10){
lines++;
if(i!=0){
for(var k=i-1; k>=0; k--){
board[k+1] = board[k];
}
}
board[0] = generateBlankLine();
}
}
return lines;
}
//擦除整个面板
function eraseBoard(){
for(var i=0; i<18; i++){
for(var j=0; j<10; j++){
tbl.rows[i].cells[j].style.backgroundColor = "white";
}
}
}
//重绘整个面板
function paintBoard(){
for(var i=0;i<18;i++){
for(var j=0; j<10; j++){
if(board[i][j]==1){
tbl.rows[i].cells[j].style.backgroundColor = "red";
}
}
}
}
//产生一个空白行.
function generateBlankLine(){
var line = new Array(10);
for(var i=0; i<10; i++){
line[i] = 0;
}
return line;
}
//更新分数
function updateScore(){
document.getElementById("score").innerText=" " + score;
}
//键盘控制
function keyControl(){
if(status!=1){
return;
}
var code = event.keyCode;
switch(code){
case 37:{
moveLeft();
break;
}
case 38:{
rotate();
break;
}
case 39:{
moveRight();
break;
}
case 40:{
moveDown();
break;
}
}
}
//开始
function begin(e){
e.disabled = true;
status = 1;
tbl = document.getElementById("board");
if(!generateBlock()){
alert("Game over!");
status = 2;
return;
}
paint();
timer = setInterval(moveDown,1000);
}
document.οnkeydοwn=keyControl;
</script>
<body>
<Input type="button" value="begin" οnclick="begin(this);"/> Score: <span id="score"> 0</span>
 
<table id="board" cellspacing=0 cellpadding=0 border=1 style="border-collapse:collapse;">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值