溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用canvas怎么實(shí)現(xiàn)一個俄羅斯方塊

發(fā)布時間:2021-04-14 15:43:07 來源:億速云 閱讀:185 作者:Leah 欄目:web開發(fā)

本篇文章給大家分享的是有關(guān)使用canvas怎么實(shí)現(xiàn)一個俄羅斯方塊,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

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

整個面板就是以左上角(0,0)為原點(diǎn)的坐標(biāo)系,右上角(12,0)左下角(0,20)右下角(12,20),每個點(diǎn)的坐標(biāo)位置都可以確定。是否已經(jīng)填充方塊,我們可以將每個方格看成一個數(shù)組元素,0表示沒有,1表示已經(jīng)填充。12 * 20 的面板使用兩層數(shù)組,即用20個長度為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], ...];

畫出面板的代碼,用最基礎(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怎么實(shí)現(xiàn)一個俄羅斯方塊

結(jié)合上面介紹的坐標(biāo)系,數(shù)組 [x1, y1, x2, y2, x3, y3, x4, y4] 就是上面圖形中4個點(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]];

方塊的移動,遍歷整個數(shù)組,加上位移向量就行,非常簡單

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)動,還會旋轉(zhuǎn),不是嗎?稍微思考下就知道,這不過就是矩陣變換而已,也就是每次圖形繞中心點(diǎn)旋轉(zhuǎn)90度。我這里用數(shù)組第三個點(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;    
    }

邊界條件

主要包括如下三個方面

  • 方塊位置不能超出界面的判斷;

  • 方塊到達(dá)底部或放置完成的判斷;

  • 游戲結(jié)束的判斷。

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

如果坐標(biāo)的y+1已經(jīng)有填充,同時當(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)動周期結(jié)束時檢測每一層是否滿格,以及滿格后的處理。某項(xiàng)數(shù)組全部元素都為1則表示已經(jīng)滿格,那么刪除該項(xiàng)數(shù)組,同時列表頭再壓入一項(xiàng)每個元素都為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);
}

以上就是使用canvas怎么實(shí)現(xiàn)一個俄羅斯方塊,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI