首页 > 作文

Html5 小游戏 俄罗斯方块

更新时间:2023-04-03 09:41:44 阅读: 评论:0

导言

在一个风和日丽的一天,看完了疯狂html 5+css 3+javascript讲义,跟着做了书里最后一章的俄罗斯方块小游戏,并做了一些改进,作为自己前端学习的第一站。

游戏效果:

制作思路

因为书里的俄罗斯方块比较普通,太常规了,不是很好看,所以我在网上找了上面那张图片,打算照着它来做。(请无视成品和原图的差距)

然后便是游戏界面和常规的俄罗斯方块游戏逻辑。

接着便是游我在伊朗长大影评戏结束界面了。

原本想做个弹出层,但觉得找图片有点麻烦,所以就在网上找了文字特效,套用了一下。

代码实现:

首先是html文件和css文件,主要涉及了布局方面。作为新手,在上面真的是翻来覆去的踩坑。o(╥﹏╥)o

index.html

<!doctype html><html><head>    <title>俄罗斯方块</title>    <meta http-equiv="content-type" content="text/html;chart=utf-8"/>    <link rel=stylesheet type="text/css" href="teris.css">    <style type="text/css">        /*导入外部的字体文件小学班务工作计划*/        @font-face{            font-family:tmb;/*为字体命名为tmb*/            src:url("ds-digib.ttf") format("truetype");/*format为字体文件格式,truetype为ttf*/        }        div>span{            font-family:tmb;            font-size:18pt;            color:green;        }    </style></head><body>    <div id="container" class="bg">        <!--ui-->        <div class="ui_bg">            <div style="float:left;margin-right:4px;">                速度:<span id="cur_speed">1</span>            </div>            <div style="float:left;">                当前分数:<span id="辱华留学生cur_points">0</span>            </div>            <div style="float:right;">                最高分数:<span id="max_points">0</span>            </div>        </div>        <canvas id="text" width="500" height="100" style="position:absolute;"></canvas>        <canvas id="stage" width="500" height="100" style="position:absolute;"></canvas>    </div>    <script src='eapack.min.js'></script>    <script src='tweenlite.min.js'></script>    <script src='ealjs-0.7.1.min.js'></script>    <script src='requestanimationframe.js'></script>    <script type="text/javascript" src="jquery-3.4.1.min.js"></script>    <script type="text/javascript" src="teris.js"></script></body></html>

teris.css

*{    margin:0;    padding:0;}html, body{    width:100%;    height:100%;}.bg{    font-size:13pt;    background-color:rgb(239, 239, 227);    /*好看的渐变色*/    background-image:radial-gradient(rgb(239, 239, 227), rgb(230, 220, 212));    /*阴影*/    box-shadow:#cdc8c1 -1px -1px 7px 0px;    padding-bottom:4px;}.ui_bg{    border-bottom:1px #a69e9ea3 solid;    padding-bottom:2px;    overflow:hidden;/*没有这句的话因为子div都设置了float,所以是浮在网页上的,所以父div就没有高度,这句清除了浮动,让父div有了子div的高度*/}

然后是重头戏,teris.js

游戏变量

//游戏设定var tetris_rows = 20;var tetris_cols = 14;var cell_size = 24;var no_block=0;var have_block=1;// 定义几种可能出现的方块组合var blockarr = [    // z    [        {x: tetris_cols / 2 - 1 , y:0},        {x: tetris_cols / 2 , y:0},        {x: tetris_cols / 2 , y:1},        {x: tetris_cols / 2 + 1 , y:1}    ],    // 反z    [        {x: tetris_cols / 2 + 1 , y:0},        {x: tetris_cols / 2 , y:0},        {x: tetris_cols / 2 , y:1},        {x: tetris_cols / 2 - 1 , y:1}    ],    // 田    [        {x: tetris_cols / 2 - 1 , y:0},        {x: tetris_cols / 2 , y:0},        {x: tetris_cols / 2 - 1 , y:1},        {x: tetris_cols / 2 , y:1}    ],    // l    [        {x: tetris_cols / 2 - 1 , y:0},        {x: tetris_cols / 2 - 1, y:1},        {x: tetris_cols / 2 - 1 , y:2},        {x: tetris_cols / 2 , y:2}    ],    // j    [        {x: tetris_cols / 2  , y:0},        {x: tetris_cols / 2 , y:1},        {x: tetris_cols / 2  , y:2},        {x: tetris_cols / 2 - 1, y:2}    ],    // □□□□    [        {x: tetris_cols / 2 , y:0},        {x: tetris_cols / 2 , y:1},        {x: tetris_cols / 2 , y:2},        {x: tetris_cols / 2 , y:3}    ],    // ┴    [        {x: tetris_cols / 2 , y:0},        {x: tetris_cols / 2 - 1 , y:1},        {x: tetris_cols / 2 , y:1},        {x: tetris_cols / 2 + 1, y:1}    ]];// 记录当前积分var curscore=0;// 记录曾经的最高积分var maxscore=1;var curspeed=1;//ui元素var curspeedele=document.getelementbyid("cur_speed");var curscoreele=document.getelementbyid("cur_points");var maxscoreele=document.getelementbyid("max_points");var timer;//方块下落控制var mycanvas;var canvasctx;var tetris_status;//地图数据var currentfall;//当前下落的block

游戏界面的完善

//create canvasfunction createcanvas(){    mycanvas=document.createelement("canvas");    mycanvas.width=tetris_cols*cell_size;    mycanvas.height=tetris_rows*cell_size;    //绘制背景    canvasctx=mycanvas.getcontext("2d");    canvasctx.beginpath();    //tetris_cos    for(let i=1; i<tetris_cols; i++){        canvasctx.moveto(i*cell_size, 0);        canvasctx.lineto(i*cell_size, mycanvas.height);    }    for(let i=1; i<tetris_rows; i++){        canvasctx.moveto(0, i*cell_size);        canvasctx.lineto(mycanvas.width, i*cell_size);    }    canvasctx.clopath();    canvasctx.strokestyle="#b4a79d";    canvasctx.linewidth=0.6;    canvasctx.stroke();    //第一行,最后一行,第一列,最后一列粗一点。    canvasctx.beginpath();    canvasctx.moveto(0, 0);    canvasctx.lineto(mycanvas.width, 0);    canvasctx.moveto(0, mycanvas.height);    canvasctx.lineto(mycanvas.width, mycanvas.height);    canvasctx.moveto(0, 0);    canvasctx.lineto(0, mycanvas.height);    canvasctx.moveto(mycanvas.width, 0);    canvasctx.lineto(mycanvas.width, mycanvas.height);    canvasctx.clopath();    canvasctx.strokestyle="#b4a79d";    canvasctx.linewidth=4;    canvasctx.stroke();    //设置绘制block时的style    canvasctx.fillstyle="#201a14";}
 1 function changewidthandheight(w, h){ 2     //通过jquery设置css 3     h+=$("ui_bg").css("height")+$("ui_bg").css("margin-rop")+$("ui_bg").css("margin-bottom")+$("ui_bg").css("padding-top")+$("ui_bg").css("padding-bottom"); 4     $(".bg").css({ 5         "width":w, 6         "height":h, 7         "top":0, "bottom":0, "right":0, "left":0, 8         "margin":"auto" 9     });10 }
 1 //draw blocks 2 function drawblocks(){ 3     //清空地图 4     for(let i=0; i<tetris_rows;i++){ 5         for(let j=0;j<tetris_cols;j++) 6             canvasctx.clearrect(j*cell_size+1, i*cell_size+1, cell_size-2, cell_size-2); 7     } 8     //绘制地图 9     for(let i=0; i<tetris_rows;i++){10         for(let j=0;j<tetris_cols;j++){11             if(tetris_status[i][j]!=no_block)12                 canvasctx.fillrect(j*cell_size+1, i*cell_size+1, cell_size-2, cell_size-2);//中间留点缝隙13         }14     }15     //绘制currentfall16     for(let i=0;i<currentfall.length;i++)17         canvasctx.fillrect(currentfall[i].x*cell_size+1, currentfall[i].y*cell_size+1, cell_size-2,cell_size-2);18 }

游戏逻辑

 1 function rotate(){ 2     // 定义记录能否旋转的旗标 3     var canrotate = true; 4     for (var i = 0 ; i < currentfall.length ; i++) 5     { 6         var prex = currentfall[i].x; 7         var prey = currentfall[i].y; 8         // 始终以第三个方块作为旋转的中心, 9         // i == 2时,说明是旋转的中心10         if(i != 2)11         {12             // 计算方块旋转后的x、y坐标13             var afterrotatex = currentfall[2].x + prey - currentfall[2].y;14             var afterrotatey = currentfall[2].y + currentfall[2].x - prex;15             // 如果旋转后所在位置已有方块,表明不能旋转16             if(tetris_status[afterrotatey][afterrotatex + 1] != no_block)17             {18                 canrotate = fal;19                 break;20             }21             // 如果旋转后的坐标已经超出了最左边边界22             if(afterrotatex < 0 || tetris_status[afterrotatey - 1][afterrotatex] != no_block)23             {24                 moveright();25                 afterrotatex = currentfall[2].x + prey - currentfall[2].y;26                 afterrotatey = currentfall[2].y + currentfall[2].x - prex;27                 break;28             }29             if(afterrotatex < 0 || tetris_status[afterrotatey-1][afterrotatex] != no_block)30             {31                 moveright();32                 break;33             }34             // 如果旋转后的坐标已经超出了最右边边界35             if(afterrotatex >= tetris_cols - 1 || 36                 tetris_status[afterrotatey][afterrotatex+1] != no_block)37             {38                 moveleft();39                 afterrotatex = currentfall[2].x + prey - currentfall[2].y;40                 afterrotatey = currentfall[2].y + currentfall[2].x - prex;41                 break;42             }43             if(afterrotatex >= tetris_cols - 1 || 44                 tetris_status[afterrotatey][afterrotatex+1] != no_block)45             {46                 moveleft();47                 break;48             }49         }50     }51     if(canrotate){52         for (var i = 0 ; i < currentfall.length ; i++){53             var prex = currentfall[i].x;54             var prey = currentfall[i].y;55             if(i != 2){56                 currentfall[i].x = currentfall[2].x + 57                     prey - currentfall[2].y;58                 currentfall[i].y = currentfall[2].y + 59                     currentfall[2].x - prex;60             }61         }62         localstorage.titem("currentfall", json.stringify(currentfall));63     }64 }
 1 //按下 下 或 interval到了 2 function next(){ 3     if(movedown()){ 4         //记录block 5         for(let i=0;i<currentfall.length;i++) 6             tetris_status[currentfall[i].y][currentfall[i].x]=have_block; 7         //判断有没有满行的 8         for元宵节的来历和风俗(let j=0;j<currentfall.length;j++){ 9             for(let i=0;i<tetris_cols; i++){10                 if(tetris_status[currentfall[j].y][i]==no_block)11                     break;12                 //最后一行满了13                 if(i==tetris_cols-1){14                     //消除最后一行15                     for(let i=currentfall[j].y; i>0;i--){16                         for(let j=0;j<tetris_cols;j++)17                             tetris_status[i][j]=tetris_status[i-1][j];18                     }19                     //分数增加20                     curscore+=5;21                     localstorage.titem("curscore", curscore);22                     if(curscore>maxscore){23                         //超越最高分24                         maxscore=curscore;25                         localstorage.titem("maxscore", maxscore);26                     }27                     //加速28                     curspeed+=0.1;29                     localstorage.titem("curspeed", curspeed);30                     //ui输出31                     curscoreele.innerhtml=""+curscore;32                     maxscoreele.innerhtml=""+maxscore;33                     curspeedele.innerhtml=curspeed.tofixed(1);//保留两位小数34                     clearinterval(timer);35                     timer=tinterval(function(){36                         next();37                     }, 500/curspeed);38                 }39             }40         }41         //判断是否触顶42         for(let i=0;i<currentfall.length;i++){43             if(currentfall[i].y==0){44                 gameend();45                 return;46             }47         }48         localstorage.titem("tetris_status", json.stringify(tetris_status));49         //新的block50         createblock();51         localstorage.titem("currentfall", json.stringify(currentfall));52     }53     drawblocks();54 }55 56 //右移57 function moveright(){58     for(let i=0;i<currentfall.length;i++){59         if(currentfall[i].x+1>=tetris_rows || tetris_status[currentfall[i].y][currentfall[i].x+1]!=no_block)60             return;61     }62     for(let i=0;i<currentfall.length;i++)63         currentfall[i].x++;64     localstorage.titem("currentfall", json.stringify(currentfall));65     return;66 }67 //左移68 function moveleft(){69     for(let i=0;i<currentfall.length;i++){70         if(currentfall[i].x-1<0 || tetris_status[currentfall[i].y][currentfall[i].x-1]!=no_block)71             return;72     }73     for(let i=0;i<currentfall.length;i++)74         currentfall[i].x--;75     localstorage.titem("currentfall", json.stringify(currentfall));76     return;77 }78 //judge can move down and if arrive at end return 1, if touch other blocks return 2, el, return 079 function movedown(){80     for(let i=0;i<currentfall.length;i++){81         if(currentfall[i].y>=tetris_rows-1 || tetris_status[currentfall[i].y+1][currentfall[i].x]!=no_block)82             return true;83     }84 85     for(let i=0;i<currentfall.length;i++)86         currentfall[i].y+=1;87     return fal;88 }
 1 function gamekeyevent(evt){ 2     switch(evt.keycode){ 3         //向下 4         ca 40://↓ 5         ca 83://s 6             next(); 7             drawblocks(); 8             break; 9         //向左10         ca 37://←11         ca 65://a12             moveleft();13             drawblocks();14             break;15         //向右16         ca 39://→17         ca 68://d18             moveright();19             drawblocks();20             break;21         //旋转22         ca 38://↑23         ca 87://w24         虎年祝福语    rotate();25             drawblocks();26             break;27     }28 }

其他的详细情况可以看源代码,我就不整理了。

接下来我们看游戏结束时的特效。因为我也不是很懂,所以在这里整理的会比较详细。当做学习。

 1 //game end 2 function gameend(){ 3     clearinterval(timer); 4     //键盘输入监听结束 5     window.onkeydown=function(){ 6         //按任意键重新开始游戏 7         window.onkeydown=gamekeyevent; 8         //初始化游戏数据 9         initdata();10         createblock();11         localstorage.titem("currentfall", json.stringify(currentfall));12         localstorage.titem("tetris_status", json.stringify(tetris_status));13         localstorage.titem("curscore", curscore);14         localstorage.titem("curspeed", curspeed);15         //绘制16         curscoreele.innerhtml=""+curscore;17         curspeedele.innerhtml=curspeed.tofixed(1);//保留两位小数18         drawblocks();19         timer=tinterval(function(){20             next();21         }, 500/curspeed);22         //清除特效23         this.stage.removeallchildren();24         this.textstage.removeallchildren();25     };26     //特效,游戏结束27     ttimeout(function(){28         initanim();29         //擦除黑色方块30         for(let i=0; i<tetris_rows;i++){31             for(let j=0;j<tetris_cols;j++)32                 canvasctx.clearrect(j*cell_size+1, i*cell_size+1, cell_size-2, cell_size-2);33         }34     }, 200);35     //推迟显示failed36     ttimeout(function(){37         if(textformed) {38             explode();39             ttimeout(function() {40                 createtext("failed");41             }, 810);42         } el {43             createtext("failed");44         }45     }, 800);46 }

上面代码里的localstorage是html5的本地数据存储。因为不是运用很难,所以具体看代码。

整个特效是运用了createjs插件。要引入几个文件。

ealjs-0.7.1.min.js,eapacj.min.js,requestanimationframe.js和tweenlite.min.js
游戏重新开始就要清除特效。我看api里我第一眼望过去最明显的就是removeallchildren(),所以就选了这个。其他的改进日后再说。

        //清除特效        this.stage.removeallchildren();        this.textstage.removeallchildren();
function initanim() {    initstages();    inittext();    initcircles();    //在stage下方添加文字——按任意键重新开始游戏.    tmp = new createjs.text("t", "12px 'source sans pro'", "#54555c");    tmp.textalign = 'center';    tmp.x = 180;    tmp.y=350;    tmp.text = "按任意键重新开始游戏";    stage.addchild(tmp);    animate();}

上面初始化了一个stage,用于存放特效,一个textstage,用于形成“failed”的像素图片。还有一个按任意键重新游戏的提示。同时开始每隔一段时间就刷新stage。

根据block的位置来初始化小圆点。

 1 function initcircles() { 2     circles = []; 3     var p=[]; 4     var count=0; 5     for(let i=0; i<tetris_rows;i++) 6         for(let j=0;j<tetris_cols;j++) 7             if(tetris_status[i][j]!=no_block) 8                 p.push({'x':j*cell_size+2, 'y':i*cell_size+2, 'w':cell_size-3, 'h':cell_size-4}); 9     for(var i=0; i<250; i++) {10         var circle = new createjs.shape();11         var r = 7;12         //x和y范围限定在黑色block内13         var x = p[count]['x']+p[count]['w']*math.random();14         var y = p[count]['y']+p[count]['h']*math.random();15         count++;16         if(count>=p.length)17             count=0;18         var color = colors[math.floor(i%colors.length)];19         var alpha = 0.2 + math.random()*0.5;20         circle.alpha = alpha;21         circle.radius = r;22         circle.graphics.beginfill(color).drawcircle(0, 0, r);23         circle.x = x;24         circle.y = y;25         circles.push(circle);26         stage.addchild(circle);27         circle.movement = 'float';28         tweencircle(circle);29     }30 }

然后再讲显示特效failed的createtext()。先将failed的text显示在textstage里,然后ctx.getimagedata.data获取像素数据,并以此来为每个小圆点定义位置。

 1 function createtext(t) { 2     curtext=t; 3     var fontsize = 500/(t.length); 4     if (fontsize > 80) fontsize = 80; 5     text.text = t; 6     text.font = "900 "+fontsize+"px 'source sans pro'"; 7     text.textalign = 'center'; 8     text.x = tetris_cols*cell_size/2; 9     text.y = 0;10     textstage.addchild(text);11     textstage.update();12 13     var ctx = document.getelementbyid('text').getcontext('2d');14     var pix = ctx.getimagedata(0,0,600,200).data;15     textpixels = [];16     for (var i = pix.length; i >= 0; i -= 4) {17         if (pix[i] != 0) {18             var x = (i / 4) % 600;19             var y = math.floor(math.floor(i/600)/4);20             if((x && x%8 == 0) && (y && y%8 == 0)) textpixels.push({x: x, y: y});21         }22     }23 24     formtext();25     textstage.clear();//清楚text的显示26 }

跟着代码的节奏走,我们现在来到了formtext.

 1 function formtext() { 2     for(var i= 0, l=textpixels.length; i<l; i++) { 3         circles[i].originx = offtx + textpixels[i].x; 4         circles[i].originy = offty + textpixels[i].y; 5         tweencircle(circles[i], 'in'); 6     } 7     textformed = true; 8     if(textpixels.length < circles.length) { 9         for(var j = textpixels.length; j<circles.length; j++) {10             circles[j].tween = tweenlite.to(circles[j], 0.4, {alpha: 0.1});11         }12     }13 }

explode()就是讲已组成字的小圆点给重新遣散。

动画实现是使用了tweenlite.

 1 function tweencircle(c, dir) { 2     if(c.tween) c.tween.kill(); 3     if(dir == 'in') { 4         /*tweenlite.to 改变c实例的x坐标,y坐标,使用eainout弹性函数,透明度提到1,改变大小,radius,总用时0.4s*/ 5         c.tween = tweenlite.to(c, 0.4, {x: c.originx, y: c.originy, ea:quad.eainout, alpha: 1, radius: 5, scalex: 0.4, scaley: 0.4, oncomplete: function() { 6             c.movement = 'jiggle';/*轻摇*/ 7             tweencircle(c); 8         }}); 9     } el if(dir == 'out') {10         c.tween = tweenlite.to(c, 0.8, {x: window.innerwidth*math.random(), y: window.innerheight*math.random(), ea:quad.eainout, alpha: 0.2 + math.random()*0.5, scalex: 1, scaley: 1, oncomplete: function() {11             c.movement = 'float';12             tweencircle(c);13         }});14     } el {15         if(c.movement == 'float') {16             c.tween = tweenlite.to(c, 5 + math.random()*3.5, {x: c.x + -100+math.random()*200, y: c.y + -100+math.random()*200, ea:quad.eainout, alpha: 0.2 + math.random()*0.5,17                 oncomplete: function() {18                     tweencircle(c);19                 }});20         } el {21             c.tween = tweenlite.to(c, 0.05, {x: c.originx + math.random()*3, y: c.originy + math.random()*3, ea:quad.eainout,22                 oncomplete: function() {23                     tweencircle(c);24                 }});25         }26     }27 }

tweenlite.to函数第一个参数,要做动画的实例,第二个参数,事件,第三个参数,动画改变参数。

quad.eainout()意思是在动画开始和结束时缓动。 oncomplete动画完成时调用的函数。易得,在我们的应用中,我们将开始下一次动画。

个人感言

其实刚开始没想做这么复杂,所以文件排的比较随意,然后就导致了后期项目完成时那副杂乱无章的样子。^_^,以后改。等我等看懂动画效果时在说,现在用的有点半懵半懂。

这篇博客写得有点乱。新手之作,就先这样吧。同上,以后改。因为不知道这个项目会不会拿来直接当我们计算机职业实践的作业。要是的话,我就彻改,连同博客。

以下是源代码地址。

还在审核。明天再说。相信我,我在小番茄里做了记录。

本文发布于:2023-04-03 09:41:42,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/30e5bfc04bf5a29c567c150fdd53428c.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Html5 小游戏 俄罗斯方块.doc

本文 PDF 下载地址:Html5 小游戏 俄罗斯方块.pdf

标签:游戏   特效   方块   坐标
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图