国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > HTML > 正文

canvas實(shí)現(xiàn)俄羅斯方塊的方法示例

2024-08-26 00:21:12
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

好久沒(méi)使用canvas了,于是通過(guò)寫(xiě)小游戲“俄羅斯方塊”再次熟悉下canvas,如果有一定的canvas基礎(chǔ),要實(shí)現(xiàn)還是不難的。

原理詳解

看游戲最終界面,可知需要實(shí)現(xiàn)以下關(guān)鍵功能:

  • 游戲面板,也就是12 * 20的方格,以及是否填充了方塊信息;
  • 運(yùn)動(dòng)方塊,方塊需要實(shí)現(xiàn)移動(dòng),變形的功能。 
     

 canvas,俄羅斯方塊

界面的實(shí)現(xiàn)

整個(gè)面板就是以左上角(0,0)為原點(diǎn)的坐標(biāo)系,右上角(12,0)左下角(0,20)右下角(12,20),每個(gè)點(diǎn)的坐標(biāo)位置都可以確定。是否已經(jīng)填充方塊,我們可以將每個(gè)方格看成一個(gè)數(shù)組元素,0表示沒(méi)有,1表示已經(jīng)填充。12 * 20 的面板使用兩層數(shù)組,即用20個(gè)長(zhǎng)度為12的數(shù)組實(shí)現(xiàn)。

var maps = [[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,1,0,1,0], ...];

畫(huà)出面板的代碼,用最基礎(chǔ)的canvas的api就能實(shí)現(xiàn)

//格子    for(var i=0;i<12;i++){        for(var j=0;j<20;j++){            ctx.fillRect(i*40,j*40,40,40);            ctx.strokeRect(i*40,j*40,40,40);            if(this.maps[j][i]==1){//方格已經(jīng)有填充內(nèi)容                ctx.save();                ctx.lineWidth=4;                ctx.fillStyle='hsla(200,100%,50%,.5)';                ctx.strokeStyle='hsla(200,100%,50%,.9)';                ctx.fillRect(i*40,j*40,40,40);                ctx.strokeRect(i*40+2,j*40+2,38,38);                ctx.restore();            }        }    }    //邊框    ctx.lineWidth=4;    ctx.strokeStyle='hsla(0,100%,0%,.3)';    ctx.moveTo(0,0);    ctx.lineTo(0,20*40);    ctx.lineTo(12*40,20*40);    ctx.lineTo(12*40,0);    ctx.stroke();    ctx.restore();

方塊的實(shí)現(xiàn)

游戲中用到以下 7 種圖形

canvas,俄羅斯方塊

結(jié)合上面介紹的坐標(biāo)系,數(shù)組 [x1, y1, x2, y2, x3, y3, x4, y4] 就是上面圖形中4個(gè)點(diǎn)坐標(biāo)的數(shù)據(jù)表現(xiàn)形式,7 種圖形的坐標(biāo)分別如下:

var Arr = [[4,0,4,1,5,1,6,1],[4,1,5,1,6,1,6,0],[4,0,5,0,5,1,6,1],[4,1,5,0,5,1,6,0],[5,0,4,1,5,1,6,1],[4,0,5,0,6,0,7,0],[5,0,6,0,5,1,6,1]];

方塊的移動(dòng),遍歷整個(gè)數(shù)組,加上位移向量就行,非常簡(jiǎn)單

class Shape {    constructor(m){        this.m = Object.assign([],m);    }    move(x,y){ // 位移        var m = this.m,            l = m.length;        y = y||0;        for (var i=0;i<l;i=i+2){            m[i]+=x;            m[i+1]+=y;        }        return this;    }

方塊的旋轉(zhuǎn),俄羅斯方塊里面方塊除了左右和上下運(yùn)動(dòng),還會(huì)旋轉(zhuǎn),不是嗎?稍微思考下就知道,這不過(guò)就是矩陣變換而已,也就是每次圖形繞中心點(diǎn)旋轉(zhuǎn)90度。我這里用數(shù)組第三個(gè)點(diǎn)作為圖形變換的中心點(diǎn),當(dāng)然這樣處理不夠完善。

class Shape {    transform(){//二維矩陣變換        var m =this.m,            l = m.length,            c = Math.ceil(l/2),            x = m[c],            y = m[c+1],            cos = Math.cos(Math.PI/180 * 90),            sin = Math.sin(Math.PI/180 * 90);        for (var i=0;i<l;i=i+2){            if(i == c) continue;            var mx = m[i]- x,                my = m[i+1] - y,                nx = mx*cos - my*sin,                ny = my*cos + mx*sin;            m[i]=x+nx;            m[i+1]=y+ny;        }        return this;        }

邊界條件

主要包括如下三個(gè)方面

  • 方塊位置不能超出界面的判斷;
  • 方塊到達(dá)底部或放置完成的判斷;
  • 游戲結(jié)束的判斷。

遍歷數(shù)組 (1)任意一個(gè)點(diǎn)y坐標(biāo)為19時(shí)表示到達(dá)了底部;(2)獲取該坐標(biāo)的y+1位置在maps的信息,如果為1表示已經(jīng)填充。這兩種情況下,運(yùn)動(dòng)方塊的周期結(jié)束,將該方塊的坐標(biāo)填充到maps對(duì)應(yīng)的數(shù)組里面即可。

如果坐標(biāo)的y+1已經(jīng)有填充,同時(shí)當(dāng)前坐標(biāo)小于1,即已經(jīng)在界面的頂部了,那么表示游戲結(jié)束。

var isEnd = false,isOver=false,x,y;for(var i=0,sl=that.shape.m.length;i<sl;i=i+2){    x=that.shape.m[i];    y=that.shape.m[i+1];    if(y >= 19){ // 到了底部        isEnd = true;break;    }    if(that.maps[y+1][x]==1){ // y+1位置已經(jīng)填充        isEnd = true;        if(y <= 1){isOver=true;} // 游戲結(jié)束        break;    }}

方塊運(yùn)動(dòng)周期結(jié)束時(shí)檢測(cè)每一層是否滿格,以及滿格后的處理。某項(xiàng)數(shù)組全部元素都為1則表示已經(jīng)滿格,那么刪除該項(xiàng)數(shù)組,同時(shí)列表頭再壓入一項(xiàng)每個(gè)元素都為0的數(shù)組即可。

checkPoint(){    var that = this,        maps = that.maps;    for(var i=0,l=maps.length;i<l;i++){        if(Math.min.apply(null,maps[i]) == 1){// 表示該層已經(jīng)滿格            that.maps.splice(i,1);            that.score+=10; // 增加分?jǐn)?shù)            that.maps.unshift([0,0,0,0,0,0,0,0,0,0,0,0]);        }    }    return this;}

綁定事件

主要就是綁定keydown事件,要注意的是左移和右移事件包括了邊界判斷

bindEvent(){    var that = this;    document.addEventListener('keydown',function(e){        switch(e.keyCode){            case 13:        //enter                cancelAnimationFrame(that.timer);                that.init().update();            break;            case 80:        //p                that.pause = !that.pause;                break;              case 40:        //down                that.d = 0.5;                break;            case 37:        //left                var over = false,                    maps = that.maps,                    shape = that.shape,                    m = shape.m;                for(var i=0,l=m.length;i<l;i=i+2){                    if(m[i]<=0 || maps[m[i+1]][m[i]-1] == 1){                        over = true;break;                    }                }                if(!over) shape.move(-1,0);                break;            case 39:        //right                var over = false,                    shape = that.shape,                    maps = that.maps,                    m = shape.m;                for(var i=0,l=m.length;i<l;i=i+2){                    if(m[i]>=11 || maps[m[i+1]][m[i]+1] == 1){                        over = true;break;                    }                }                if(!over) shape.move(1,0);                break;            case 32:        //space                that.shape.transform();                break;        }    },false);}

總結(jié)

這里面實(shí)現(xiàn)了俄羅斯方塊的最基本功能,還有關(guān)卡等功能點(diǎn)并沒(méi)有實(shí)現(xiàn),同時(shí)該demo仍然有不完善的地方需要修正。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到HTML教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 德化县| 贡嘎县| 巫溪县| 曲周县| 克什克腾旗| 弥渡县| 崇礼县| 库车县| 河曲县| 建昌县| 罗甸县| 辽宁省| 常宁市| 嘉义县| 东乡族自治县| 丹巴县| 碌曲县| 高密市| 五大连池市| 通海县| 洛川县| 峨眉山市| 攀枝花市| 阿拉善右旗| 防城港市| 枣庄市| 比如县| 正定县| 滁州市| 天等县| 兴宁市| 息烽县| 安阳市| 新干县| 蒙阴县| 凌源市| 高淳县| 湛江市| 宁陕县| 琼结县| 东方市|