Bevor ich mit dem Text beginne, möchte ich etwas sagen, das sich auf die Entwicklung dieses Spiels bezieht, ohne auf irgendwelche Designideen Bezug zu nehmen Würden Sie nicht mit halbem Aufwand das doppelte Ergebnis erzielen? Natürlich gibt es Vorteile, wenn man auf beides verweist, und ich werde nur auf die Vorteile eingehen, wenn ich eine Arbeit nach mühsamen Bemühungen und Dutzenden von Fehlern fertigstelle Modifikationen kann ich anderen mit Stolz sagen: „Sehen Sie, ich habe dieses Spiel entwickelt!“ Natürlich liegt die Kreativität nicht bei mir, aber das berührt meine „Eitelkeit“ nicht. Wäre es nicht interessant, einem klassischen Spiel mein Eigen zu machen? Wenn ich zurückblicke und mir die Ideen anderer Leute anschaue, frage ich mich manchmal: „Warum bin ich nicht schon früher darauf gekommen?“, „Also kann dieses Problem so gelöst werden“, „Diese Designidee ist viel besser als meine!“ usw. sind viel besser, als sich nur die Ideen anderer Leute anzusehen und das eigene Denken von Anfang an zu blockieren, oder?
Okay, der Text beginnt~
Wenn Sie den Effekt zuerst sehen möchten, springen Sie und probieren Sie es aus!
Tetris, die Hauptspieloberfläche sollte aus Blöcken bestehen, wie unten gezeigt. Natürlich sind diese Gitter im fertigen Produkt nicht zu sehen Wenn die Schnittstellengröße 400×500 beträgt, stellen Sie die Größe jedes Ziegels (Gitter) auf 20×20 ein, dann gibt es 20 Ziegel in jeder Reihe und 25 Ziegel in jeder Spalte. Zugehöriger Code:
brickWidth = 20, //砖块大小 width = 400, height = 500; //画布宽高,20X25
Wenn es um das Raster der Hauptschnittstelle geht, müssen wir eine sehr wichtige Variable< erwähnen 🎜> Ja, es ist BOARD, ein zweidimensionales Array . Optisch ist seine Größe 20×26. Der gespeicherte Wert ist 0 oder 1. 0 bedeutet, dass sich an dieser Position kein Baustein befindet, und 1 Das bedeutet, dass an dieser Position Blöcke bei einigen der folgenden Entscheidungen eine wichtige Rolle spielen. Schüler, die mit dem Spiel vorsichtig sind, können herausfinden, warum es 20×26 ist, was dem Hauptschnittstellenraster entspricht Stellen Sie es auch zu Beginn auf 20 × 25 ein. Später bemerkte ich, dass, wenn ich eine Zeile hinzufüge und der Wert dieser Zeile 1 ist, leicht beurteilt werden kann, ob der Stein den unteren Rand der Hauptschnittstelle berührt hat. Zugehöriger Code:
// 初始化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; } } }
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() { …… } //变换砖头朝向
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] ] //次行为翻转的情况];
Horizontales Umdrehen des Bildes ), die zweite Dimension ist die Richtung (oben, links, unten, rechts) und die dritte Dimension ist die Verteilung der vier Steine der Form I Definieren Sie jede neue Form Objekt in In einem 4×4-Array ist beispielsweise Tus this.embattle[0][0] [0,4,5,8] und die Zahl ist die Position von der Ziegel, wie unten gezeigt:
Um die Position und das Aussehen einer Form zu bestimmen, ist isOverturn erforderlich, um festzustellen, ob sie umgedreht ist, und eine Richtung, um ihre Richtung zu bestimmen , und originX und originY sind erforderlich, um die Position des „Arrays“ zu bestimmen. Als nächstes werden die vier Prototypmethoden von Brick erläutert.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方法的结果是什么了吗?事实上,它不应该成功改变方向的,对吧?还有其他一些卡位的情况。
Die 4 Prototyp-Methoden von Brick werden hier vorgestellt. Wenn ich nun die nächste Form in der Informationsoberfläche auf der rechten Seite anzeigen möchte, besteht der direkteste Weg darin, ein Objekt über den -Konstruktor der Form zu instanziieren. Um zu verhindern, dass es automatisch autoMove aufruft, habe ich den Konstruktor isModel hinzugefügt um festzustellen, ob es für Eingabeaufforderungen verwendet wird.
Es gibt auch wichtige Ereignis-Überwachung, LöschenObj. Der Einstieg in das Spiel ist einfach NextBrick-Funktion.
Außerdem bin ich mir nicht sicher, ob deleteObj den GC tatsächlich erfolgreich veranlasst hat, das Objekt zu recyceln.
Außerdem wollte ich ursprünglich eine Level-Funktion hinzufügen, da die Geschwindigkeit (Geschwindigkeitsvariable) frei eingestellt werden kann, also habe ich diese Funktion beiseite gelegt.
Das obige ist der detaillierte Inhalt vonPraktische Erstellung von HTML5 Tetris (Bilder und Text). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!