站長資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        動手打造html5俄羅斯方塊的(圖文)

        在正文開始之前還要啰嗦一下,標題中所謂自給自足,是在沒有參考任何設計思路的前提下去開發(fā)這游戲的,你可能會不解,如果參考優(yōu)秀的思路,豈不是事半功倍,當然,參考與不參考都有利,我只說不參考的利,當我煞費苦心、歷經(jīng)數(shù)十個BUG修改,終于完成一件作品的時候,我可以很自豪地對別人說:“看,我開發(fā)的游戲!”當然,創(chuàng)意不是我的,但這并不影響自己那份“虛榮心”,為一款經(jīng)典的游戲賦予自我的理解,并將它融入游戲中,豈不是一件有意思的事,而且,回過頭來再看一看別人的思路,有時會拍案而起,“這個我當初怎么就沒想到呢?”,“原來這個問題可以這樣解決”,“這個設計思路比我的思路好多了!”,諸如此類總比開始就直接看別人的思路而阻塞自己的思考要強得多,對吧?

        好叻,正文開始~

        想先看效果的,先跳轉(zhuǎn)試玩一下吧!

        俄羅斯方塊,主游戲界面應該由一個一個的方塊組成,如下圖,當然成品里面這些網(wǎng)格是看不到的,這里只是助于理解,主界面尺寸為400×500,設定每塊磚(網(wǎng)格)的尺寸為20×20,則每行有20個磚塊,每列有25個磚塊。相關代碼:

        brickWidth = 20,    //磚塊大小  width = 400, height = 500;  //畫布寬高,20X25

        動手打造html5俄羅斯方塊的(圖文)

        提到主界面的網(wǎng)格,就要提到一個非常重要的變量了,它就是BOARD,一個二維數(shù)組,形象化地說其尺寸是20×26,存儲的值為0或1,0表示該位置沒有磚塊,1表示該位置有磚塊,在接下來的一些判定中有重要作用,游戲細心的同學可能發(fā)現(xiàn),為什么是20×26,而不是對應主界面網(wǎng)格的20×25,我在一開始的時候也是設定為20×25的,后來注意到如果加一行而且這一行的值都為1就可以很容易判斷磚塊是否到觸及主界面底部了。相關代碼:

        // 初始化BOARD,注意縱向有26個,最后一排用來判斷是否觸底  for(i=0;i<20;i++){      BOARD[i] = [];      for(j=0;j<26;j++) {          if(j==25) {              BOARD[i][j] = 1          } else {              BOARD[i][j] = 0;          }      }  }

        動手打造html5俄羅斯方塊的(圖文)

        接下來看由4個磚塊組成的“形狀”,有五種,為了好描述,我把它們?yōu)閯e命名,Tian(田),Chu(鋤頭),Tu(凸起來),Thunder(閃電),Line(一橫),哈哈有趣的名字,原諒我沒找到它們的英文名字吧。

        首先定義一個磚頭類Brick:

        function Brick() { }

        其下有幾個原型變量和方法:

        Brick.prototype.embattle = null;    //磚塊的布局(需重載)  Brick.prototype.isOverturn = 0; //是否翻轉(zhuǎn)  Brick.prototype.originX = 9;    //磚頭的繪制起點X  Brick.prototype.originY = -3;    //磚頭的繪制起點Y  Brick.prototype.direction = 0;  //磚頭朝向  Brick.prototype.autoMoveTimer = null;   //自動移動計時器  Brick.prototype.draw = function() { …… }    //畫磚塊的方法  Brick.prototype.move = function(moveX, moveY) { …… }    //移動的方法  Brick.prototype.autoMove = function() { …… }    //自動移動的方法  Brick.prototype.change = function() { …… }    //變換磚頭朝向

        Brick的子類有:Tian,Chu,Tu,Thunder,Line五個,每個子類中都重載Brick的embattle變量,embattle是什么,英譯中的意思是布陣,這個陣是個什么陣呢?首先,同學們要理解我的思路,用Tu的embattle來舉例,其代碼如下:

        this.embattle = [      [ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ],  //布局表為4X4表格,數(shù)字為磚頭位置      [ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ]   //次行為翻轉(zhuǎn)的情況];

        embattle是一個三維數(shù)組,第一維是是否翻轉(zhuǎn)isOverturn(形象來說就像圖片的水平翻轉(zhuǎn)),第二維是方向direction(上左下右),第三維是形狀的4個磚塊分布情況,我把每個新形狀對象定義在一個4×4的陣中,例如,Tu的this.embattle[0][0]為[0,4,5,8],數(shù)字即該磚塊的所在位置,如下圖:

        動手打造html5俄羅斯方塊的(圖文)

        所以要確定一個形狀的位置和樣子,需要isOverturn確定是否翻轉(zhuǎn),需要direction確定其方向,需要originX和originY確定“陣”的位置。

        接下來,分別解釋Brick的4個原型方法。

        Brick.prototype.draw

        ctx.fillStyle = 'rgb('+Math.floor(Math.random()*256)+','+Math.floor(Math.random()*256)+',  '+Math.floor(Math.random()*256)+')';  for(i=0;i<4;i++) {      tmp = this.embattle[this.isOverturn][this.direction][i];      ctx.fillRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);      ctx.strokeRect((this.originX+tmp%4)*brickWidth+1, (this.originY+Math.floor(tmp/4))*brickWidth+1, brickWidth-2, brickWidth-2);   //注意+1和減2  }

        有上面說的確定形狀的位置和樣子的方法,之后就是純粹canvas畫圖,4個磚塊一個一個地畫,不要看代碼很長其實就是那么一點點,originX、originY和磚塊在陣中的位置就可以確定畫磚塊的起點了。注意到代碼的注釋了沒有,畫邊框的時候,它是從起點向外面畫的,就像我把一個塑料袋套在另一個塑料袋的外面,為了以后的清除的方便且不影響其他的磚塊,把邊框畫進fillRect的領土,就像我現(xiàn)在把這個塑料袋不套在外面而是放進這另一個塑料袋里面一樣,就這個意思。

        Brick.prototype.move

        這是最長的一個了,移動的時候,moveX和moveY表示橫縱的增量,沒有同時非0的情況(這是人為的設定,要么橫向移動要么縱向移動),當然要判斷即將移動到的位置是否違規(guī):

        橫向:

        如果陣貼靠主界面左側則不能向左移即moveX不能為-1

        (this.originX==0 && moveX==-1)

        判斷右邊時比較麻煩,因為不能直接用陣來判斷是否貼靠右側(看前面的圖就知道陣的右邊和下邊可能沒有磚塊的),這時要一個個地判斷4個磚塊是否有至少有一個在最右,這時不能向右移動

        || (this.originX+tmp[0]%4==19 && moveX==1)  || (this.originX+tmp[1]%4==19 && moveX==1)  || (this.originX+tmp[2]%4==19 && moveX==1)  || (this.originX+tmp[3]%4==19 && moveX==1)

        最后還要判斷即將到達的位置是否已經(jīng)有磚塊了。

        || (BOARD[this.originX+tmp[0]%4+moveX][this.originY+Math.floor(tmp[0]/4)]==1)  || (BOARD[this.originX+tmp[1]%4+moveX][this.originY+Math.floor(tmp[1]/4)]==1)  || (BOARD[this.originX+tmp[2]%4+moveX][this.originY+Math.floor(tmp[2]/4)]==1)  || (BOARD[this.originX+tmp[3]%4+moveX][this.originY+Math.floor(tmp[3]/4)]==1)

        縱向:

        即將到達的位置是否已經(jīng)有磚塊了,注意到下面的代碼的&& moveX==0,原來是沒有的,后來發(fā)現(xiàn)每次磚塊怎么剛剛靠上下面堆著的磚塊就不能再移動了,原來橫向移動的時候也進行了這個判斷,即剛剛靠上下面的磚塊,如果這時想左右移動,但下方有磚塊,但是問題來了,下面有沒有磚塊跟我左右移動有什么關系呢?是吧。

        if((as==1 || bs==1 || cs==1 || ds==1) && moveX==0) { …… }

        縱向終止判斷里面主要做了幾件事:清除autoMoveTimer,設置BOARD在該形狀當前位置的值為1,有可以消除的整行就消除,加分改分,判斷勝利/失敗,刪除當前對象,召喚下一個形狀。

        橫縱都沒違規(guī)時:

        這時,把該形狀前一個位置的磚塊清除,更新originX和originY,再畫出來。

        for(i=0;i<4;i++) {      tmp = this.embattle[this.isOverturn][this.direction][i];      ctx.clearRect((this.originX+tmp%4)*brickWidth, (this.originY+Math.floor(tmp/4))*brickWidth, brickWidth, brickWidth);  }  this.originX += moveX;  this.originY += moveY;  this.draw();

        Brick.prototype.autoMove

        只做一件事,設置計時器,定時向下移動。

        var status, self = this;this.autoMoveTimer = setInterval(function() {      status = self.move(0,1);  },speed);

        Brick.prototype.change

        改變形狀的朝向,很好辦啊,不是有embattle數(shù)組了嗎?當然沒有那么簡單,不只是換個數(shù)組這么簡單。要考慮改變方向之后占用的位置是否已經(jīng)有磚塊了,如果形狀是貼著主界面右邊界就更糟糕了,比如原來是豎著的Line,改變其方向變?yōu)闄M,占用陣的0、1、2、3,如果Line貼著右邊界,originX為19,變?yōu)闄M向,占用陣的0、1、2、3,后面三個磚塊已經(jīng)溢出了主界面。

        動手打造html5俄羅斯方塊的(圖文)

        解決方案是:如果有越界的磚塊就把陣往左挪一挪,直到不再越界。

        while(ox+tmp[0]%4 > 19 || ox+tmp[1]%4 > 19 || ox+tmp[2]%4 > 19 || ox+tmp[3]%4 > 19) {      ox -= 1;  }

        最后,如果都沒事,就可以清除原位置,畫出改變方向之后的形狀了。

        并不是太完美,因為有些卡位的情況沒考慮進來,什么是卡位,看下圖,你知道Line實例調(diào)用change方法的結果是什么了嗎?事實上,它不應該成功改變方向的,對吧?還有其他一些卡位的情況。

        動手打造html5俄羅斯方塊的(圖文)

        Brick的4個原型方法就介紹到這里了。現(xiàn)在如果我要在右邊的信息界面顯示下一個的形狀,最直接的方法就是,通過該形狀的構造函數(shù)實例化一個對象,為防止其自動調(diào)用autoMove,為構造函數(shù)添加了isModel來判斷是不是供提示用的。

        還有按鍵事件監(jiān)聽、NextBrick函數(shù)和deleteObj自己看看吧,很容易看懂,游戲的入口就是NextBrick函數(shù)。

        還有就是,我無法確定deleteObj是否真的成功讓GC把對象回收了。

        還有就是,我本想增加關卡功能,因為可以自由設置速度(speed變量),就把這功能放一放了。

        贊(0)
        分享到: 更多 (0)
        網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
        主站蜘蛛池模板: 日韩精品无码AV成人观看| 热re99久久精品国99热| 亚洲欧洲精品无码AV| 亚洲成人精品久久| 国精品无码一区二区三区左线| 欧美XXXX黑人又粗又长精品| 亚洲第一精品福利| 国产精品福利在线观看| 久久久精品人妻一区二区三区蜜桃| 日韩精品无码免费视频| 国内精品久久久久久久亚洲| 97精品国产高清自在线看超| 精品久久久久久久久中文字幕| 精品久久久久久无码专区不卡| 欲帝精品福利视频导航| 日韩精品成人亚洲专区| 精品97国产免费人成视频| 91无码人妻精品一区二区三区L| 97精品伊人久久大香线蕉app| 无码人妻精品一区二区三区久久 | 99久久精品国产综合一区 | 亚洲精品国产成人片| 人妻偷人精品成人AV| 久久五月精品中文字幕| 久久精品综合一区二区三区| 精品久久久久久无码中文野结衣| 国产精品国产三级国产潘金莲| 91精品国产麻豆国产自产在线 | 无夜精品久久久久久| 久久久久九九精品影院| 国产精品亚洲w码日韩中文| 亚洲综合国产精品| 午夜精品美女自拍福到在线| 色综合久久综精品| 91无码人妻精品一区二区三区L| 国产成人精品久久一区二区三区av | 国产高清在线精品二区一| 国产精品岛国久久久久| 久久久久夜夜夜精品国产| 色综合久久综精品| 国产呦小j女精品视频|