久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

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

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

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

      好叻,正文開始~

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

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

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

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

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

      // 初始化BOARD,注意縱向有26個(gè),最后一排用來(lái)判斷是否觸底  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;          }      }  }

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

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

      首先定義一個(gè)磚頭類Brick:

      function Brick() { }

      其下有幾個(gè)原型變量和方法:

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

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

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

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

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

      接下來(lái),分別解釋Brick的4個(gè)原型方法。

      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  }

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

      Brick.prototype.move

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

      橫向:

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

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

      判斷右邊時(shí)比較麻煩,因?yàn)椴荒苤苯佑藐噥?lái)判斷是否貼靠右側(cè)(看前面的圖就知道陣的右邊和下邊可能沒(méi)有磚塊的),這時(shí)要一個(gè)個(gè)地判斷4個(gè)磚塊是否有至少有一個(gè)在最右,這時(shí)不能向右移動(dòng)

      || (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)

      最后還要判斷即將到達(dá)的位置是否已經(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)

      縱向:

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

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

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

      橫縱都沒(méi)違規(guī)時(shí):

      這時(shí),把該形狀前一個(gè)位置的磚塊清除,更新originX和originY,再畫出來(lái)。

      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

      只做一件事,設(shè)置計(jì)時(shí)器,定時(shí)向下移動(dòng)。

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

      Brick.prototype.change

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

      動(dò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;  }

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

      并不是太完美,因?yàn)橛行┛ㄎ坏那闆r沒(méi)考慮進(jìn)來(lái),什么是卡位,看下圖,你知道Line實(shí)例調(diào)用change方法的結(jié)果是什么了嗎?事實(shí)上,它不應(yīng)該成功改變方向的,對(duì)吧?還有其他一些卡位的情況。

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

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

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

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

      還有就是,我本想增加關(guān)卡功能,因?yàn)榭梢宰杂稍O(shè)置速度(speed變量),就把這功能放一放了。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)