千家信息网

html5如何实现俄罗斯方块小游戏

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,这篇文章将为大家详细讲解有关html5如何实现俄罗斯方块小游戏,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。制作思路因为书里的俄罗斯方块比较普通,太常规了,不是很好
千家信息网最后更新 2025年01月18日html5如何实现俄罗斯方块小游戏

这篇文章将为大家详细讲解有关html5如何实现俄罗斯方块小游戏,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

制作思路

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

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

接着便是游戏结束界面了。

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

代码实现:

首先是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 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

游戏逻辑

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;jmaxScore){                        //超越最高分                        maxScore=curScore;                        localStorage.setItem("maxScore", maxScore);                    }                    //加速                    curSpeed+=0.1;                    localStorage.setItem("curSpeed", curSpeed);                    //ui输出                    curScoreEle[xss_clean]=""+curScore;                    maxScoreEle[xss_clean]=""+maxScore;                    curSpeedEle[xss_clean]=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

keydown事件监听

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

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

//game endfunction 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[xss_clean]=""+curScore;        curSpeedEle[xss_clean]=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; i

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

动画实现是使用了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如何实现俄罗斯方块小游戏"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

0