在正文開始之前還要囉嗦一下,標題中所謂自給自足,是在沒有參考任何設計思路的前提下去開發這遊戲的,你可能會不解,如果參考優秀的思路,豈不是事半功倍,當然,參考與不參考都有利,我只說不參考的利,當我煞費苦心、歷經數十個BUG修改,終於完成一件作品的時候,我可以很自豪地對別人說:「看,我開發的遊戲! ,回過頭來再看一看別人的思路,有時會拍案而起,“這個我當初怎麼就沒想到呢?”,“原來這個問題可以這樣解決”,“這個設計思路比我的思路好多了! ”,諸如此類總比開始就直接看別人的思路而阻塞自己的思考要強得多,對吧?
好叻,正文開始~
想先看效果的,先跳轉試試看吧!
俄羅斯方塊,主遊戲介面應該由一個一個的方塊組成,如下圖,當然成品裡面這些網格是看不到的,這裡只是助於理解,主介面尺寸為400× 500,設定每塊磚(網格)的尺寸為20×20,則每行有20個磚塊,每列有25個磚塊。 相關程式碼:
brickWidth = 20, //砖块大小 width = 400, height = 500; //画布宽高,20X25
提到主介面的網格,就要提到一個非常重要的變數了,它就是BOARD,一個二維數組,形象化地說其尺寸是20×26,儲存的值為0或1,0表示該位置沒有磚塊,1表示該位置有磚塊,在接下來的一些判定中有重要作用,遊戲細心的同學可能發現,為什麼是20×26,而不是對應主界面網格的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; } } }
#接下來看由4個磚塊組成的“形狀”,有五種,為了好描述,我把它們為別命名,Tian(田),Chu(鋤頭),Tu(凸起來),Thunder(閃電),Line(一橫),哈哈有趣的名字,原諒我沒找到它們的英文名字吧。
先定義一個磚頭類別Brick:
function Brick() { }
其下有幾個原型變數和方法:
Brick.prototype.embattle = null; //砖块的布局(需重载) Brick.prototype.isOverturn = 0; //是否翻转 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表格,数字为砖头位置 [ [0,4,5,8], [1,4,5,6], [1,4,5,9], [0,1,2,5] ] //次行为翻转的情况];
embattle是一個三維數組,第一維是是否翻轉isOverturn(形象來說就像圖片的水平翻轉),第二維是方向direction(上左下右),第三維是形狀的4個磚塊分佈情況,我把每個新形狀物件定義在一個4 ×4的陣中,例如,Tu的this.embattle[0][0]為[0,4,5,8],數字即該磚塊的所在位置,如下圖:
所以要確定一個形狀的位置和樣子,需要isOverturn確定是否翻轉,需要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的领土,就像我现在把这个塑料袋不套在外面而是放进这另一个塑料袋里面一样,就这个意思。
Brick.prototype.move
这是最长的一个了,移动的时候,moveX和moveY表示横纵的增量,没有同时非0的情况(这是人为的设定,要么横向移动要么纵向移动),当然要判断即将移动到的位置是否违规:
横向:
如果阵贴靠主界面左侧则不能向左移即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)
最后还要判断即将到达的位置是否已经有砖块了。
|| (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)
纵向:
即将到达的位置是否已经有砖块了,注意到下面的代码的&& moveX==0,原来是没有的,后来发现每次砖块怎么刚刚靠上下面堆着的砖块就不能再移动了,原来横向移动的时候也进行了这个判断,即刚刚靠上下面的砖块,如果这时想左右移动,但下方有砖块,但是问题来了,下面有没有砖块跟我左右移动有什么关系呢?是吧。
if((as==1 || bs==1 || cs==1 || ds==1) && moveX==0) { …… }
纵向终止判断里面主要做了几件事:清除autoMoveTimer,设置BOARD在该形状当前位置的值为1,有可以消除的整行就消除,加分改分,判断胜利/失败,删除当前对象,召唤下一个形状。
横纵都没违规时:
这时,把该形状前一个位置的砖块清除,更新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数组了吗?当然没有那么简单,不只是换个数组这么简单。要考虑改变方向之后占用的位置是否已经有砖块了,如果形状是贴着主界面右边界就更糟糕了,比如原来是竖着的Line,改变其方向变为横,占用阵的0、1、2、3,如果Line贴着右边界,originX为19,变为横向,占用阵的0、1、2、3,后面三个砖块已经溢出了主界面。
解决方案是:如果有越界的砖块就把阵往左挪一挪,直到不再越界。
while(ox+tmp[0]%4 > 19 || ox+tmp[1]%4 > 19 || ox+tmp[2]%4 > 19 || ox+tmp[3]%4 > 19) { ox -= 1; }
最后,如果都没事,就可以清除原位置,画出改变方向之后的形状了。
并不是太完美,因为有些卡位的情况没考虑进来,什么是卡位,看下图,你知道Line实例调用change方法的结果是什么了吗?事实上,它不应该成功改变方向的,对吧?还有其他一些卡位的情况。
Brick的4個原型方法就介紹到這裡了。現在如果我要在右邊的信息界面顯示下一個的形狀,最直接的方法就是,通過該形狀的構造函數實例化一個對象,為防止其自動調用autoMove,為構造函數添加了isModel來判斷是不是供提示用的。
還有按鍵事件監聽、NextBrick函數和deleteObj自己看看吧,很容易看懂,遊戲的入口就是NextBrick函數。
還有就是,我無法確定deleteObj是否真的成功讓GC把物件回收了。
還有就是,我本來想增加關卡功能,因為可以自由設定速度(speed變數),就把這功能放一放了。
以上是動手打造html5俄羅斯方塊的(圖文)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Web标准和技术从HTML4、CSS2和简单的JavaScript演变至今,经历了显著的发展。1)HTML5引入了Canvas、WebStorage等API,增强了Web应用的复杂性和互动性。2)CSS3增加了动画和过渡功能,使页面效果更加丰富。3)JavaScript通过Node.js和ES6的现代化语法,如箭头函数和类,提升了开发效率和代码可读性,这些变化推动了Web应用的性能优化和最佳实践的发展。

H5不僅僅是HTML5的簡稱,它代表了一個更廣泛的現代網頁開發技術生態:1.H5包括HTML5、CSS3、JavaScript及相關API和技術;2.它提供更豐富、互動、流暢的用戶體驗,能在多設備上無縫運行;3.使用H5技術棧可以創建響應式網頁和復雜交互功能。

H5與HTML5指的是同一個東西,即HTML5。 HTML5是HTML的第五個版本,帶來了語義化標籤、多媒體支持、畫布與圖形、離線存儲與本地存儲等新功能,提升了網頁的表現力和交互性。

H5referstoHTML5,apivotaltechnologyinwebdevelopment.1)HTML5introducesnewelementsandAPIsforrich,dynamicwebapplications.2)Itsupportsmultimediawithoutplugins,enhancinguserexperienceacrossdevices.3)SemanticelementsimprovecontentstructureandSEO.4)H5'srespo

H5開發需要掌握的工具和框架包括Vue.js、React和Webpack。 1.Vue.js適用於構建用戶界面,支持組件化開發。 2.React通過虛擬DOM優化頁面渲染,適合複雜應用。 3.Webpack用於模塊打包,優化資源加載。

HTML5hassignificantlytransformedwebdevelopmentbyintroducingsemanticelements,enhancingmultimediasupport,andimprovingperformance.1)ItmadewebsitesmoreaccessibleandSEO-friendlywithsemanticelementslike,,and.2)HTML5introducednativeandtags,eliminatingthenee

H5通過語義化元素和ARIA屬性提升網頁的可訪問性和SEO效果。 1.使用、、等元素組織內容結構,提高SEO。 2.ARIA屬性如aria-label增強可訪問性,輔助技術用戶可順利使用網頁。

"h5"和"HTML5"在大多數情況下是相同的,但它們在某些特定場景下可能有不同的含義。 1."HTML5"是W3C定義的標準,包含新標籤和API。 2."h5"通常是HTML5的簡稱,但在移動開發中可能指基於HTML5的框架。理解這些區別有助於在項目中準確使用這些術語。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

記事本++7.3.1
好用且免費的程式碼編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

WebStorm Mac版
好用的JavaScript開發工具