background
When I was struggling with ES6, I suddenly remembered that I used C language to write Tetris in college. In this project, I mainly used the Class feature of ES6 to conduct object-oriented programming. The project adopts Node.js V6.2.0 + electron V1.1.0 for desktop development, which can run across all platforms.
Train of thought
-
Comprehensive application of object-oriented design ideas, so that the functional cohesion is strong.
-
Think of the seven cubes as separate “creatures” that can “see” the world around them.
-
Instead of using the traditional large two-dimensional array to represent the state of the game scene, let Tetris “see” it for itself.
-
Using HTML5 canvas is more like CGI programming.
-
Using the least amount of canvas features, fillRect, strokeRect, getImageData, clearRect etc. Several functions.
rendering
I played the highest record ^_^
Operation method
Js V6.2.0 + electron V1.1.0 is used for desktop development, so please install related systems first:
npm install electron-prebuilt -gCopy the code
Note: This project can run across all platforms. In case of permission problems, please add sudo on the command line.
The source code:
Git clone https://git.oschina.net/zhoutk/Tetris.git or: git clone https://github.com/zhoutk/TetrisCopy the code
Enter the project directory:
cd TetrisCopy the code
Run the program:
electron .Copy the code
Critical code analysis
The functions are as cohesive as possible. The Block class encapsulates all the operations of small squares, and the Canvas interface function is basically encapsulated in this class. The Tetris class combines blocks, which encapsulate most Tetris operations.
Block class (small Block class)
class Block{ constructor(ctx,fillColor,strokeColor){ this.ctx = ctx; // Canvas object this.width = BLOCKWIDTH; / / small square side length enclosing fillColor = fillColor | | 'blue'. / / fill continuously color this. StrokeColor = strokeColor | | 'white'. Draw (x,y){this.ctx.save(); this.ctx.fillStyle = this.fillColor; this.ctx.fillRect(x*this.width + 1,y*this.width + 1,this.width-2,this.width-2) this.ctx.strokeStyle = this.strokeColor; this.ctx.strokeRect(x*this.width + 1,y*this.width + 1,this.width-2,this.width-2); this.ctx.restore(); } erase(x,y){this.ctx.clearRect(x*this.width,y *this.width, 30, 0, 0);} erase(x,y){this.ctx.clearRect(x*this.width,y *this.width, 30, 0); 30)} canSee (x, y) {/ / see if a location is empty let c = this. CTX. GetImageData (x * enclosing width + 9, y * enclosing width + 9,1,1) return c.d ata [0] | c.data[1] | c.data[2] | c.data[3]; } getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y){getColor(x,y)} 'rgba('+c.data[0]+','+c.data[1]+','+c.data[2]+','+c.data[3]+')'; }}Copy the code
Tetris
The class Tetris {constructor (shape, CTX, x, y) {this. Data = [,0,0,0 [0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]. / / square shape data. This shape = shape | | 0; // Block shape code this. CTX = CTX; / / this canvas object. X = x | | 0; / / square location data this. Y = y | | 0; this.block = new Block(ctx, COLORS[shape]); For (let I = 0; i < SHAPES[this.shape].length; I++) {/ / square shape to initialize the if (SHAPES [. This shape] [I]) {this. Data [4] I % [1 + Math. Floor (I / 4)] = 1; } } } cleanup(){ ... } // moveNext(){... } // Move the block down one space moveLeft(){... } // Move the square one space left moveRight(){... } // Move the block one space right moveDown(){... Rotate (){rotate(); rotate(); rotate(); } // Square rotation canDrawNext(){... } // check whether the new block can be placed, the game ends check draw(){... } // call the block object and draw tetris erase(){... } // Call the block object to do the Tetris erase canSee{... } // Call the block object to detect the Tetris placementCopy the code
Block.canSee
Take the color attribute of the specified location pixel to simulate the “vision” of the box.
CanSee (x, y) {let c = this. CTX. GetImageData (x * enclosing width + 9, y * enclosing width + 9,1,1) return c.d ata [0] | c.d ata [1] | c.d ata [2] | c.data[3]; // Black indicates all zeros, xor is 0, the position is empty, other indicates that the position is occupied. }Copy the code
Tetris.cleanup
Elimination layer is more complex, with notes.
cleanup(){ let h = 19, levelCount = 0; While (h >= 0){let count = 0; For (let I = 0; i< 10; I++) {/ / traverse a layer of the if (this. CanSee (I, h)) {/ / position is empty, add a count++ variables; } if(count == 0){let level = h; // levelCount++; // SOUNDS['score']. Play (); While (level >= 0){// let ct = 0; For (let j = 0; j < 10; j++){ this.block.erase(j,level); If (this.cansee (j,level-1)){this.cansee (j,level-1); } else {let bk = new / / vertical grid color Block above (enclosing CTX, enclosing Block. The getColor (j, level 1) defending the draw (j, level) / / down}} the if (ct = = 10) { // The first floor is empty and the whole move down is completed in advance. break; }else{ level--; }}}else if(count == 10){// If (count == 10){ break; }else{ h--; } } return levelCount; }Copy the code
Tetris.moveNext
Moving the box down one layer is more complicated, with a note.
moveNext(){ let flag = true; // For (let I = 0; i < 4; I++){for(let j = 0; j < 4; j++){ if(this.data[i][j] && (j ==3 || this.data[i][j+1] == 0)){ if(! this.canSee(this.x + i, this.y + 1 + j)){ flag = false; // break to the end; } } } if(! flag){ break; }} if(flag){this.erase(); this.y++; this.draw(); return true; }else{let level = this.cleanup(); If (level > 0){// Level += level; // scores += LVSCS[level] document.getelementById ('levelShow'). Value = levels; document.getElementById('scoreShow').value = scores; if(Math.floor(scores / STEPVAL) ! ClearInterval (interval) interval = setInterval(tick, TICKVAL - ++STEP * STEPVAL); document.getElementById('speedShow').value = STEP + 1; } }else{ SOUNDS['down'].play() } return false; }}Copy the code
Operation and Rules
-
Direction up key: Rotate
-
Direction left: move left
-
Right direction: Move right
-
Direction down key: Move down
-
Space bar: move down to the bottom
-
Scoring: at the same time the elimination of a layer count 1 point; Second floor 3 points; Three layers 3 points; Four layers is
-
There are ten classes of speed, each 50ms apart
summary
The project is currently in v1.0.0 and has all the basic features of the Tetris game complete with sound effects. In the future, I consider network fighting, man-machine fighting, machine fighting. I mainly wanted to experiment with artificial intelligence, starting with letting algorithms play Tetris by themselves!