I haven’t used canvas for a long time, so I got familiar with canvas again by writing the small game Tetris. If you have a certain canvas foundation, it is not difficult to implement.
Detailed explanation of the principleLooking at the final interface of the game, we can see that the following key functions need to be implemented:
The entire panel is a coordinate system with the upper left corner (0,0) as the origin, the upper right corner (12,0), the lower left corner (0,20), and the lower right corner (12,20). The coordinate position of each point can be determined. Whether the square has been filled, we can think of each square as an array element, 0 means not, 1 means it has been filled. The 12 * 20 panel uses two layers of arrays, that is, 20 arrays with a length of 12 are implemented.
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], ...];
The code for drawing the panel can be implemented using the most basic canvas API.
//Grid 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){//The square has been filled with content 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(); } } } //Border 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();Implementation of blocks
The following 7 graphics are used in the game
Combined with the coordinate system introduced above, the array [x1, y1, x2, y2, x3, y3, x4, y4] is the data representation of the coordinates of the four points in the above graphics. The coordinates of the seven graphics are as follows:
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]];
To move the block, just traverse the entire array and add the displacement vector. It is very simple.
class Shape { constructor(m){ this.m = Object.assign([],m); } move(x,y){ // Displacement 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; }
Rotation of blocks. In addition to moving left and right and up and down, the blocks in Tetris also rotate, right? After a little thought, you will know that this is just a matrix transformation, that is, each time the shape is rotated 90 degrees around the center point. I use the third point in the array as the center point of the graphics transformation. Of course, this processing is not perfect.
class Shape { transform(){//Two-dimensional matrix transformation 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; }boundary conditions
It mainly includes the following three aspects
Traverse the array (1) When the y coordinate of any point is 19, it means it has reached the bottom; (2) Get the information about the y+1 position of the coordinate in the maps. If it is 1, it means it has been filled. In both cases, when the period of the moving block ends, just fill the coordinates of the block into the array corresponding to maps.
If the y+1 of the coordinate has been filled and the current coordinate is less than 1, that is, it is already at the top of the interface, then the game is over.
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){ // At the bottom isEnd = true;break; } if(that.maps[y+1][x]==1 ){ // The y+1 position has been filled isEnd = true; if(y <= 1){isOver=true;} // The game is over break; }}
At the end of the block movement cycle, it is checked whether each layer is full, and the processing after the square is full. If all the elements of a certain array are 1, it means that the grid is full. Then delete the array, and at the same time push an array with each element of 0 into the head of the list.
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){// Indicates that the layer is full that.maps.splice(i,1); that.score+=10; // Increase the score that.maps.unshift([0,0,0,0,0,0,0,0,0,0,0,0]); } } return this;}Binding events
The main thing is to bind the keydown event. It should be noted that the left shift and right shift events include boundary judgment.
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);}Summarize
The most basic functions of Tetris are implemented here, and functional points such as levels are not implemented. At the same time, the demo still has imperfections that need to be corrected.
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.