javascript俄罗斯方块代码

俄罗斯方块游戏实现
本文介绍了一个使用HTML和JavaScript实现的俄罗斯方块游戏。游戏具备基本功能,包括方块的移动、旋转、加速及计分等。代码经过优化,修复了部分错误并增加了级别和分数功能。

[代码] [JavaScript]代码

1只实现了基本功能。
2 
3isColorful=false;           //方块是否有颜色
4把这里的变量设置为true值,将可以显示为简单的彩色版
5 
6该文档已经做了改善,修复了下标越界的错误和修改了一些奇怪的设定和代码,而且加入了计分和级别的功能。

[文件] Tetris.html

001<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
002<html xmlns="http://www.w3.org/1999/xhtml">
003<head>
004<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
005<title>Hello World</title>
006<script type="text/javascript">
007/******************************************/
008function $(id){
009    return document.getElementById(id);
010}
011function myalert(msg){
012    $("myalertbox").value=msg;
013}
014/******************************************/
015//分数和级别统计
016var SCORE_LEVEL_INC=80;     //升价所需分数值
017var score=0,                //分数
018level=0,                    //级数
019interval_unit=25,           //随级数递增的时间间隔增量
020interval_base=300;          //时间间隔基量
021//////////////////////
022 
023 
024var widthDot=20,        //方块格宽度
025heightDot=20,           //方块格高度
026widthContainer=240,     //游戏面板宽度
027heightContainer=420,    //游戏面板高度
028rows=0,                 //游戏面板中容纳的方格行数
029cols=0,                 //列数
030widthGraph=0;           //方块宽度
031 
032var colors="#ffffff,#cccccc,#ff0000,#00ff00,#0000ff,#ffff00,#ff00ff,#00ffff,#666666";   //颜色
033 
034//方块的坐标值
035var cur_top=0, 
036cur_left=0;
037 
038var eles=null,      //方格数组
039graph=null;         //方块对象
040 
041var control_interval=50,
042main_interval=200;          //主时间实例(线程)的时间触发间隔,即方块的下降速度
043//时间实例
044var main_t=0,               //主时间实例
045control_t=0;                //控制方块操作功能的时间实例
046 
047var isPause=false,          //暂停标识
048isColorful=false;           //方块是否有颜色
049 
050//监控的事件
051document.onkeydown=keyDown;
052document.onkeyup=keyUp;
053window.onload=init;
054 
055function init(){
056    //计算并赋值变量,用以保存
057    rows=heightContainer/heightDot;
058    cols=widthContainer/widthDot;
059    eles=$("MainDiv").getElementsByTagName("DIV");
060     
061    initPanel();
062    start();
063}
064function start(){
065    graph=exportGraph(parseInt(Math.random()*7));
066    //获取方块的宽度,并保存到全局变量
067    widthGraph=0;
068    for(var i=0;i<graph.length;i++){
069        if(widthGraph<graph[i].length)widthGraph=graph[i].length;
070    }
071    ////////////////
072    cur_top=0-graph.length;
073    cur_left=parseInt((cols-widthGraph)/2);
074 
075    startDiamonds();
076}
077//启动线程触发方块运行
078function startDiamonds(){
079    if(main_t==0){
080        main_t=setInterval(function(){
081            doDownShift();
082        },main_interval);
083    }
084}
085//停止方块运行监控线程
086function stopDiamonds(){
087    clearInterval(main_t);
088    main_t=0;
089}
090//下移
091function doDownShift(){
092    if(graph==null)return;
093    if(isTouchBottom()){        //判断是否不能再继续下降
094        stopDiamonds();
095        //把方块降落地点的所有方格设置起fixed属性,代表该方格已被占用
096        for(var i=0;i<graph.length;i++){
097            for(var j=0;j<graph[i].length;j++){
098                //if(graph[i][j]==1)eles[(cur_top+i)*cols+(cur_left+j)].setAttribute("fixed",1);
099                if(graph[i][j]!=0)eles[(cur_top+i)*cols+(cur_left+j)].setAttribute("fixed",graph[i][j]);
100            }
101        }
102        //消行处理
103        clearRow();
104        start();
105        return;
106    }
107    cur_top++;
108    repaint();
109    refreshGraph();
110}
111//左移
112function doLeftShift(){
113    if(graph==null)return;
114    if(cur_left<=0)return;
115    var fixed=0;
116    for(var i=0;i<graph.length;i++){
117        if(cur_top+i<0)continue;
118        for(var j=0;j<graph[i].length;j++){  //左边数起
119            if(graph[i][j]!=0&&(cur_top+i)*cols+cur_left+j<rows*cols){   //判断是否实心方块和防止下标越界
120                fixed=eles[(cur_top+i)*cols+(cur_left+j-1)].getAttribute("fixed");
121                if(fixed!=0)return;     //判断靠左的一点是否被置点
122                break;      //只需要判断方块当前行中最左端的一个有颜色的点
123            }
124        }
125    }
126    cur_left--;
127    repaint();
128    refreshGraph();
129}
130//右移
131function doRightShift(){
132    if(graph==null)return;
133    if(cur_left>=cols-widthGraph)return;
134    var fixed=0;
135    for(var i=0;i<graph.length;i++){
136        if(cur_top+i<0)continue;
137        for(var j=graph[i].length-1;j>=0;j--){       //右边数起
138            if(graph[i][j]!=0&&(cur_top+i)*cols+cur_left+j<rows*cols){   //判断是否实心方格和防止下标访问越界
139                fixed=eles[(cur_top+i)*cols+(cur_left+j+1)].getAttribute("fixed");
140                if(fixed!=0)return;     //判断靠右的一点是否被置点
141                break;      //只需要判断方块当前行中的最右端的一个有颜色的点
142            }
143        }
144    }
145    cur_left++;
146    repaint();
147    refreshGraph();
148}
149//改变方块方向
150function doRedirection(){
151    var row=graph.length;
152    var col=widthGraph;
153    var temp=new Array(col);
154    for(var i=0;i<temp.length;i++)temp[i]=new Array();
155    for(var i=0;i<col;i++)
156        for(var j=0;j<row;j++)
157            temp[i][j]=graph[row-j-1][i];
158    //给方块重新定位
159    var incHeight=col-row;
160    var incWidth=row-col;
161    //判断当前的空间是否可以让方块改变方向
162    var tempWidth=row;
163    var temp_cur_top=cur_top-parseInt(incHeight/2);
164    var temp_cur_left=cur_left-parseInt(incWidth/2);
165    if(temp_cur_top>rows-temp.length)return;
166    if(temp_cur_left<0)return;
167    if(temp_cur_left>(cols-tempWidth))return;
168    //判断是否存在足够方块旋转的空间大小
169    var nMax=row>col?row:col;
170    for(var i=0;i<nMax;i++){
171        for(var j=0;j<nMax;j++){
172            fixed=eles[(cur_top+i)*cols+(cur_left+j)].getAttribute("fixed");
173            if(fixed!=0)return;
174        }
175    }  
176    //为全局对象赋值
177    cur_top=temp_cur_top;
178    cur_left=temp_cur_left;
179    widthGraph=tempWidth;       //方块宽度已经改变,必须重新赋值
180    graph=temp;
181     
182    repaint();
183    refreshGraph();
184}
185//加速
186function doAccelerate(){
187    if(isTouchBottom())return;
188    cur_top++;
189    repaint();
190    refreshGraph();
191}
192//刷新,重绘游戏面板
193function repaint(){
194    var fixed=0;
195    var cur=null;
196    for(var i=0;i<rows;i++){
197        for(var j=0;j<cols;j++){
198            cur=eles[i*cols+j];
199            fixed=cur.getAttribute("fixed");
200            cur.style.backgroundColor=getRandomColor(fixed);           
201        }
202    }
203}
204//刷新,重绘方块对象
205function refreshGraph(){
206    if(graph==null)return;
207    for(var i=0;i<graph.length;i++){
208        if(cur_top+i<0)continue;
209        for(var j=0;j<graph[i].length;j++){
210            if(graph[i][j]!=0){     //实心方格
211                if((cur_top+i)*cols+cur_left+j<rows*cols){   //防止下标访问越界
212                    eles[(cur_top+i)*cols+(cur_left+j)].style.backgroundColor=getRandomColor(graph[i][j]);
213                }
214            }
215        }
216    }
217}
218//是否到底部
219function isTouchBottom(){
220    if(graph==null)return;
221    if(cur_top<0)return false;   //首先判断cur_top是否超出正确的下标值,不然程序无法运行
222    if(cur_top>=rows-graph.length)return true;
223    var fixed=0;
224    for(var i=graph.length-1;i>=0;i--){  //为效率考虑,从方块底部开始扫描
225        for(var j=0;j<graph[i].length;j++){
226            //判断是否为实心方格和防止下标访问越界
227            if(graph[i][j]!=0&&(cur_top+i+1)*cols+cur_left+j<rows*cols){
228                //判断当前点的下面一个点的属性fixed是否不为0(白色),非0代表有颜色
229                fixed=eles[(cur_top+i+1)*cols+cur_left+j].getAttribute("fixed");
230                if(fixed!=0) return true;
231            }
232        }
233    }
234    return false;
235}
236//消行处理
237function clearRow(){
238    var isFilled=false; //填充标识
239    var count=0;        //消行次数
240    for(var i=rows-1;i>=0;i--){
241        isFilled=true;
242        for(var j=0;j<cols;j++){
243            if(eles[i*cols+j].getAttribute("fixed")=="0"){
244                isFilled=false;
245                break;
246            }
247        }
248        if(isFilled){
249            for(var j=0;j<cols;j++)eles[i*cols+j].setAttribute("fixed",0);
250            repaint();
251            var fixed=0;
252            //所有方块下移
253            for(var k=i-1;k>=0;k--){ //因为当前的i为被消除的一行的下标,所以应该设置k=i-1
254                for(var j=0;j<cols;j++){
255                    fixed=eles[k*cols+j].getAttribute("fixed");
256                    eles[(k+1)*cols+j].setAttribute("fixed",fixed);
257                }
258            }
259            i=i+1;      //注意这里因为所有方块已经下移,
260                        //所以必须重新修改i值让外部的循环再次扫描最近被撤销的一行 
261            count++;
262        }
263    }
264    //最高级别为9级,所以分数极限为(9+1)*SCORE_LEVEL_INC-1
265    if(score>=10*SCORE_LEVEL_INC-1)return;
266 
267    //加分规则:消除行数,1行加10分,2行加15分,3行加20分,4行加30分
268    switch(count){
269    case 1:
270        score+=10;
271        break;
272    case 2:
273        score+=15;
274        break;
275    case 3:
276        score+=20;
277        break;
278    case 4:
279        score+=30;
280        break;
281    }
282    var temp_level=parseInt(score/SCORE_LEVEL_INC);
283    if(temp_level>level){
284        //更新显示内容
285        level=temp_level;
286        $("level_span").innerHTML=level;
287        //撤销当前时间实例,然后重设
288        main_interval=interval_base-level*interval_unit;
289        stopDiamonds();
290        startDiamonds();
291    }
292    $("score_span").innerHTML=score;
293}
294function exportGraph(num){
295    var oGraph=null;
296    switch(num){
297        case 0:         //水平条
298            oGraph=[[1,1,1,1]];
299            break;
300        case 1:         //三角
301            oGraph=[[0,1,0],[1,1,1]];   //graph[0]为顶,graph[1]为底
302            break;
303        case 2:         //左横节
304            oGraph=[[1,0,0],[1,1,1]];
305            break;
306        case 3:         //右横节
307            oGraph=[[0,0,1],[1,1,1]];
308            break;
309        case 4:         //左闪电
310            oGraph=[[1,1,0],[0,1,1]];
311            break;
312        case 5:         //右闪电
313            oGraph=[[0,1,1],[1,1,0]];
314            break;
315        case 6:         //石头
316            oGraph=[[1,1],[1,1]];
317            break;
318    }
319    //附上颜色
320    if(isColorful){
321        var idx=parseInt(Math.random()*(colors.split(",").length));
322        idx=idx==0?1:idx;   //idx不应该为0
323        var temp=new Array(oGraph.length);      //只能创建临时变量temp,并重新赋值给oGraph,不然会出现奇怪的错误,原因不明
324        for(var i=0;i<temp.length;i++){
325            temp[i]=new Array();
326            for(var j=0;j<oGraph[i].length;j++){
327                if(oGraph[i][j]!=0) temp[i].push(idx);
328                else temp[i].push(0);
329            }
330        }
331        oGraph=temp;
332    }
333    return oGraph;
334}
335//根据调色板的值,获取特定颜色值
336function getRandomColor(idx){
337    var arrayColors=colors.split(",");
338    return arrayColors[idx];
339}
340function keyDown(e){
341    if(control_t!=0)return;
342    e=e||window.event;
343    switch(e.keyCode){
344        case 37:        //左移
345            if(!isPause)control_t=setInterval(doLeftShift,control_interval);
346            //doLeftShift();
347            break;
348        case 39:        //右移
349            if(!isPause)control_t=setInterval(doRightShift,control_interval);
350            //doRightShift();
351            break;
352        case 38:        //改变方向
353            //control_t=setInterval(doRedirection,control_interval);
354            if(!isPause)doRedirection();
355            break;
356        case 40:        //加速
357            if(!isPause)control_t=setInterval(doAccelerate,control_interval);
358            //doAccelerate();
359            break;
360        case 13:        //暂停或取消暂停,回车符
361            if(isPause){
362                startDiamonds();
363            }else{
364                stopDiamonds();
365            }
366            isPause=!isPause;
367            break;
368    }
369    return;
370}
371function keyUp(){
372    if(control_t==0)return;
373    clearInterval(control_t);
374    control_t=0;
375}  
376//初始化游戏,创建方格,生成游戏面板,
377function initPanel(){
378    var container=$("MainDiv");
379    container.style.width=widthContainer+"px";
380    container.style.height=heightContainer+"px";
381 
382    var row=heightContainer/heightDot;
383    var col=widthContainer/widthDot;
384    var strHtml="<table width='"+widthContainer+"' height='"+heightContainer+"' border='0' cellpadding='0' cellspacing='0'>";
385     
386    for(var i=0;i<row;i++){ 
387        strHtml+="<tr>";
388        for(var j=0;j<col;j++){
389            strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='0' style='border:solid 1px #000000; background-color:#ffffff; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
390        }
391        strHtml+="</tr>";
392    }
393    strHtml+="</table>";
394    container.innerHTML=strHtml;
395}
396</script>
397</head>
398<body>
399<input type="text" id="myalertbox" style="width:500px; height:15px; border:solid 1px #000000; position:absolute; top:10px; left:10px;" />
400<div style="margin:0 auto; margin-top:30px; width:250px; font-size:12px;">
401    <div style="width:100px; float:left; margin-left:10px; text-align:center;">分数:<span id="score_span" style="color:#ff0000">0</span></div>
402    <div style="width:100px; float:right; margin-right:10px; text-align:center;">级别:<span id="level_span" style="color:#ff0000;">0</span></div>
403</div>
404<div style="margin:0 auto; margin-top:10px; width:250px; border:solid 1px #000000; font-size:12px; clear:both;">方向键:<br />上:变形&nbsp;&nbsp;下:加速&nbsp;&nbsp;左:左移&nbsp;&nbsp;右:右移<br />回车符:暂停</div>
405<div id="MainDiv" style="margin:0 auto; margin-top:10px; padding:0px; border:solid 1px #000000;"></div>
406</body>
407</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值