小编给大家分享一下如何使用Html5写一个简单的俄罗斯方块小游戏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
创新互联长期为1000多家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为高阳企业提供专业的网站建设、网站制作,高阳网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。
游戏效果:
制作思路
因为书里的俄罗斯方块比较普通,太常规了,不是很好看,所以我在网上找了上面那张图片,打算照着它来做。(请无视成品和原图的差距)
然后便是游戏界面和常规的俄罗斯方块游戏逻辑。
接着便是游戏结束界面了。
原本想做个弹出层,但觉得找图片有点麻烦,所以就在网上找了文字特效,套用了一下。
代码实现:
首先是html文件和css文件,主要涉及了布局方面。作为新手,在上面真的是翻来覆去的踩坑。o(╥﹏╥)o
index.html
俄罗斯方块 速度:1当前分数:0最高分数:0
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 canvas function 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 function changeWidthAndHeight(w, h){ //通过jquery设置css 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"); $(".bg").css({ "width":w, "height":h, "top":0, "bottom":0, "right":0, "left":0, "margin":"auto" }); } change width and height//draw blocks function drawBlocks(){ //清空地图 for(let i=0; i游戏逻辑
function rotate(){ // 定义记录能否旋转的旗标 var canRotate = true; for (var i = 0 ; i < currentFall.length ; i++) { var preX = currentFall[i].x; var preY = currentFall[i].y; // 始终以第三个方块作为旋转的中心, // i == 2时,说明是旋转的中心 if(i != 2) { // 计算方块旋转后的x、y坐标 var afterRotateX = currentFall[2].x + preY - currentFall[2].y; var afterRotateY = currentFall[2].y + currentFall[2].x - preX; // 如果旋转后所在位置已有方块,表明不能旋转 if(tetris_status[afterRotateY][afterRotateX + 1] != NO_BLOCK) { canRotate = false; break; } // 如果旋转后的坐标已经超出了最左边边界 if(afterRotateX < 0 || tetris_status[afterRotateY - 1][afterRotateX] != NO_BLOCK) { moveRight(); afterRotateX = currentFall[2].x + preY - currentFall[2].y; afterRotateY = currentFall[2].y + currentFall[2].x - preX; break; } if(afterRotateX < 0 || tetris_status[afterRotateY-1][afterRotateX] != NO_BLOCK) { moveRight(); break; } // 如果旋转后的坐标已经超出了最右边边界 if(afterRotateX >= TETRIS_COLS - 1 || tetris_status[afterRotateY][afterRotateX+1] != NO_BLOCK) { moveLeft(); afterRotateX = currentFall[2].x + preY - currentFall[2].y; afterRotateY = currentFall[2].y + currentFall[2].x - preX; break; } if(afterRotateX >= TETRIS_COLS - 1 || tetris_status[afterRotateY][afterRotateX+1] != NO_BLOCK) { moveLeft(); break; } } } if(canRotate){ for (var i = 0 ; i < currentFall.length ; i++){ var preX = currentFall[i].x; var preY = currentFall[i].y; if(i != 2){ currentFall[i].x = currentFall[2].x + preY - currentFall[2].y; currentFall[i].y = currentFall[2].y + currentFall[2].x - preX; } } localStorage.setItem("currentFall", JSON.stringify(currentFall)); } } 旋转//按下 下 或 interval到了 function next(){ if(moveDown()){ //记录block for(let i=0;i0;i--){ for(let j=0;j maxScore){ //超越最高分 maxScore=curScore; localStorage.setItem("maxScore", maxScore); } //加速 curSpeed+=0.1; localStorage.setItem("curSpeed", curSpeed); //ui输出 curScoreEle.innerHTML=""+curScore; maxScoreEle.innerHTML=""+maxScore; curSpeedEle.innerHTML=curSpeed.toFixed(1);//保留两位小数 clearInterval(timer); timer=setInterval(function(){ next(); }, 500/curSpeed); } } } //判断是否触顶 for(let i=0;i =TETRIS_ROWS || tetris_status[currentFall[i].y][currentFall[i].x+1]!=NO_BLOCK) return; } for(let i=0;i =TETRIS_ROWS-1 || tetris_status[currentFall[i].y+1][currentFall[i].x]!=NO_BLOCK) return true; } for(let i=0;i function gameKeyEvent(evt){ switch(evt.keyCode){ //向下 case 40://↓ case 83://S next(); drawBlocks(); break; //向左 case 37://← case 65://A moveLeft(); drawBlocks(); break; //向右 case 39://→ case 68://D moveRight(); drawBlocks(); break; //旋转 case 38://↑ case 87://W rotate(); drawBlocks(); break; } } keydown事件监听keydown事件监听
其他的详细情况可以看源代码,我就不整理了。
接下来我们看游戏结束时的特效。因为我也不是很懂,所以在这里整理的会比较详细。当做学习。
//game end function gameEnd(){ clearInterval(timer); //键盘输入监听结束 window.onkeydown=function(){ //按任意键重新开始游戏 window.onkeydown=gameKeyEvent; //初始化游戏数据 initData(); createBlock(); localStorage.setItem("currentFall", JSON.stringify(currentFall)); localStorage.setItem("tetris_status", JSON.stringify(tetris_status)); localStorage.setItem("curScore", curScore); localStorage.setItem("curSpeed", curSpeed); //绘制 curScoreEle.innerHTML=""+curScore; curSpeedEle.innerHTML=curSpeed.toFixed(1);//保留两位小数 drawBlocks(); timer=setInterval(function(){ next(); }, 500/curSpeed); //清除特效 this.stage.removeAllChildren(); this.textStage.removeAllChildren(); }; //特效,游戏结束 setTimeout(function(){ initAnim(); //擦除黑色方块 for(let i=0; i上面代码里的localstorage是html5的本地数据存储。因为不是运用很难,所以具体看代码。
整个特效是运用了createjs插件。要引入几个文件。
easeljs-0.7.1.min.js,EasePacj.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(); } initAnim上面初始化了一个stage,用于存放特效,一个textstage,用于形成“FAILED”的像素图片。还有一个按任意键重新游戏的提示。同时开始每隔一段时间就刷新stage。
根据block的位置来初始化小圆点。
function initCircles() { circles = []; var p=[]; var count=0; for(let i=0; i=p.length) count=0; var color = colors[Math.floor(i%colors.length)]; var alpha = 0.2 + Math.random()*0.5; circle.alpha = alpha; circle.radius = r; circle.graphics.beginFill(color).drawCircle(0, 0, r); circle.x = x; circle.y = y; circles.push(circle); stage.addChild(circle); circle.movement = 'float'; tweenCircle(circle); } } initCircles 然后再讲显示特效Failed的createText()。先将FAILED的text显示在textstage里,然后ctx.getImageData.data获取像素数据,并以此来为每个小圆点定义位置。
function createText(t) { curText=t; var fontSize = 500/(t.length); if (fontSize > 80) fontSize = 80; text.text = t; text.font = "900 "+fontSize+"px 'Source Sans Pro'"; text.textAlign = 'center'; text.x = TETRIS_COLS*CELL_SIZE/2; text.y = 0; textStage.addChild(text); textStage.update(); var ctx = document.getElementById('text').getContext('2d'); var pix = ctx.getImageData(0,0,600,200).data; textPixels = []; for (var i = pix.length; i >= 0; i -= 4) { if (pix[i] != 0) { var x = (i / 4) % 600; var y = Math.floor(Math.floor(i/600)/4); if((x && x%8 == 0) && (y && y%8 == 0)) textPixels.push({x: x, y: y}); } } formText(); textStage.clear();//清楚text的显示 } CreateText跟着代码的节奏走,我们现在来到了formtext.
function formText() { for(var i= 0, l=textPixels.length; iexplode()就是讲已组成字的小圆点给重新遣散。
动画实现是使用了tweenlite.
function tweenCircle(c, dir) { if(c.tween) c.tween.kill(); if(dir == 'in') { /*TweenLite.to 改变c实例的x坐标,y坐标,使用easeInOut弹性函数,透明度提到1,改变大小,radius,总用时0.4s*/ c.tween = TweenLite.to(c, 0.4, {x: c.originX, y: c.originY, ease:Quad.easeInOut, alpha: 1, radius: 5, scaleX: 0.4, scaleY: 0.4, onComplete: function() { c.movement = 'jiggle';/*轻摇*/ tweenCircle(c); }}); } else if(dir == 'out') { c.tween = TweenLite.to(c, 0.8, {x: window.innerWidth*Math.random(), y: window.innerHeight*Math.random(), ease:Quad.easeInOut, alpha: 0.2 + Math.random()*0.5, scaleX: 1, scaleY: 1, onComplete: function() { c.movement = 'float'; tweenCircle(c); }}); } else { if(c.movement == 'float') { c.tween = TweenLite.to(c, 5 + Math.random()*3.5, {x: c.x + -100+Math.random()*200, y: c.y + -100+Math.random()*200, ease:Quad.easeInOut, alpha: 0.2 + Math.random()*0.5, onComplete: function() { tweenCircle(c); }}); } else { c.tween = TweenLite.to(c, 0.05, {x: c.originX + Math.random()*3, y: c.originY + Math.random()*3, ease:Quad.easeInOut, onComplete: function() { tweenCircle(c); }}); } } }TweenLite.to函数第一个参数,要做动画的实例,第二个参数,事件,第三个参数,动画改变参数。
Quad.easeInOut()意思是在动画开始和结束时缓动。onComplete动画完成时调用的函数。
以上是“如何使用Html5写一个简单的俄罗斯方块小游戏”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!
网站标题:如何使用Html5写一个简单的俄罗斯方块小游戏
分享URL:http://cdweb.net/article/ghsisp.html