The examples in this article share with you the specific code of Java implementation Tetris for your reference. The specific content is as follows
Save the game's map using a 2D array:
// Game map grid, each grid saves one square, array record the state of the block private State map[][] = new State[rows][columns];
Initialize all grids in the map to empty before the game:
/* Initialize all blocks to empty*/for (int i = 0; i < map.length; i++) { for (int j = 0; j < map[i].length; j++) { map[i][j] = State.EMPTY; }}During the game, we can see the blocks on the interface, so we have to draw all the blocks in the map. Of course, in addition to drawing the blocks, the game points and the end of the game also need to be drawn when necessary:
/** * Draw the content of the form, including game blocks, game points or end string*/@Overridepublic void paint(Graphics g) { super.paint(g); for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (map[i][j] == State.ACTIVE) { // Draw the active block g.setColor(activeColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } else if (map[i][j] == State.STOPED) { // Draw a static block g.setColor(stopedColor); g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25, BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5, BLOCK_SIZE / 5); } } } /* Print score*/ g.setColor(scoreColor); g.setFont(new Font("Times New Roman", Font.BOLD, 30)); g.drawString("SCORE : " + totalScore, 5, 70); // The game ends, print the end string if (!isGoingOn) { g.setColor(Color.RED); g.setFont(new Font("Times New Roman", Font.BOLD, 40)); g.drawString("GAME OVER !", this.getWidth() / 2 - 140, this.getHeight() / 2); }}Several types of graphics composed of squares are generated by random numbers. Generally, seven types of graphics: bar, field, regular 7, reverse 7, T-shaped, Z-shaped and inverse Z-shaped, such as generating bars:
map[0][randPos] = map[0][randPos - 1] = map[0][randPos + 1] = map[0][randPos + 2] = State.ACTIVE;
After generating the graphics, the whereabouts are implemented. If you encounter obstacles, you cannot continue to fall:
isFall = true; // Whether it can fall// Check from the current line, stop the fall if an obstacle is encountered for (int i = 0; i < blockRows; i++) { for (int j = 0; j < columns; j++) { // If the block in the line is an active block, the block is a static block, the block is encountered if (map[rowIndex - i][j] == State.ACTIVE && map[rowIndex - i + 1][j] == State.STOPED) { isFall = false; // Stop the fall break; } } if (!isFall) break;}If no obstacle is encountered, the block diagram will move down one line as a whole:
// The graph falls a row for (int i = 0; i < blockRows; i++) { for (int j = 0; j < columns; j++) { if (map[rowIndex - i][j] == State.ACTIVE) { // The active block moves down one row map[rowIndex - i][j] = State.EMPTY; // The original active block becomes an empty block map[rowIndex - i + 1][j] = State.ACTIVE; // The next line of block becomes an active block} }}A similar operation is when moving to the left and right:
/** * Go left*/private void left() { // Mark whether there is an obstacle on the left boolean hasBlock = false; /* Check whether there is an obstacle on the left*/ for (int i = 0; i < blockRows; i++) { if (map[rowIndex - i][0] == State.ACTIVE) { // Check whether the left is a wall hasBlock = true; break; // There is an obstacle, do not need to loop to judge the row} else { for (int j = 1; j < columns; j++) { // Check whether there are other blocks on the left if (map[rowIndex - i][j] == State.ACTIVE && map[rowIndex - i][j - 1] == State.STOPED) { hasBlock = true; break; // There is an obstacle, no need to recycle the judgment column} } if (hasBlock) break; // There is an obstacle, no need to recycle the judgment row} } /* There is no obstacle on the left, move the figure to the left by the distance of a block*/ if (!hasBlock) { for (int i = 0; i < blockRows; i++) { for (int j = 1; j < columns; j++) { if (map[rowIndex - i][j] = State.EMPTY; map[rowIndex - i][j - 1] = State.ACTIVE; } } } // Repaint repaint(); }}When moving downward, it reduces the time interval for each normal state falls:
/** * Go straight down*/private void down() { // Marks can accelerate the fall immediately = true;}How to change the direction of the graph, only a very simple method is used here to achieve direction transformation. Of course, there can be a better algorithm to implement direction transformation operations. You can study it yourself:
/** * Rotate the square shape*/private void rotate() { try { if (shape == 4) { // Square, the same shape is returned before and after rotation; } else if (shape == 0) { // Strip// Temporary array, place the figure after rotation State[][] tmp = new State[4][4]; int startColumn = 0; // Find the first square position at the beginning of the figure for (int i = 0; i < columns; i++) { if (map[rowIndex][i] == State.ACTIVE) { startColumn = i; break; } } // Find out if there is an obstacle after rotation. If there is an obstacle, do not rotate for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (map[rowIndex - 3 + i][j + startColumn] == State.STOPED) { return; } } } } if (map[rowIndex][startColumn + 1] == State.ACTIVE) { // Horizontal bar, transform into a vertical bar for (int i = 0; i < 4; i++) { tmp[i][0] = State.ACTIVE; for (int j = 1; j < 4; j++) { tmp[i][j] = State.EMPTY; } } blockRows = 4; } else { // Vertical bar, transform into horizontal bar for (int j = 0; j < 4; j++) { tmp[3][j] = State.ACTIVE; for (int i = 0; i < 3; i++) { tmp[i][j] = State.EMPTY; } } blockRows = 1; } // Modify the graph in the original map to a transformed graph for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { map[rowIndex - 3 + i][startColumn + j] = tmp[i][j]; } } } else { // Temporary array, place the rotation of the figure State[][] tmp = new State[3][3]; int startColumn = columns; // Find the first block position at the beginning of the figure for (int j = 0; j < 3; j++) { for (int i = 0; i < columns; i++) { if (map[rowIndex - j][i] == State.ACTIVE) { startColumn = i < startColumn ? i : startColumn; } } } // Determine whether there will be obstacles after transformation for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (map[rowIndex - 2 + j][startColumn + 2 - i] == State.STOPED) return; } } // Transform for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { tmp[2 - j][i] = map[rowIndex - 2 + i][startColumn + j]; } } // Modify the graph in the original map to the transformed graph for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { map[rowIndex - 2 + i][startColumn + j] = tmp[i][j]; } } // Repaint repaint(); // Remove the line pointer for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (map[rowIndex - i][startColumn + j] != null || map[rowIndex - i][startColumn + j] != State.EMPTY) { rowIndex = rowIndex - i; blockRows = 3; return; } } } } } } catch (Exception e) { // If an array subscript is encountered, it means that the shape of the graph cannot be changed and no processing is done}}When the figure falls and stops when it encounters obstacles, we need to determine whether there is a certain line or several lines that can be eliminated. At this time, we can first obtain the number of squares in each line, and then make a judgment:
int[] blocksCount = new int[rows]; // Record the number of columns with blocks per row int eliminateRows = 0; // Number of rows eliminated/* Calculate the number of blocks per row*/for (int i = 0; i < rows; i++) { blocksCount[i] = 0; for (int j = 0; j < columns; j++) { if (map[i][j] == State.STOPED) blocksCount[i]++; }}If there is a full row of blocks, the row of blocks will be eliminated:
/* Implement block elimination operation with full rows*/for (int i = 0; i < rows; i++) { if (blocksCount[i] == columns) { // Clear a line for (int m = i; m >= 0; m--) { for (int n = 0; n < columns; n++) { map[m][n] = (m == 0) ? State.EMPTY : map[m - 1][n]; } } eliminateRows++; // Record the number of eliminated rows}}Finally, we can repaint the points and display them.
Repeat the above operations of generating graphics, falling graphics, moving left and right, and judging the elimination line, and a simple Tetris will be completed.
Running effect:
Complete sample code: Tetris
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.