<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                {% raw %} # Java 俄羅斯方塊 > 原文: [https://zetcode.com/tutorials/javagamestutorial/tetris/](https://zetcode.com/tutorials/javagamestutorial/tetris/) 在本章中,我們將在 Java Swing 中創建一個俄羅斯方塊游戲克隆。 源代碼和圖像可以在作者的 Github [Java-Tetris-Game](https://github.com/janbodnar/Java-Tetris-Game) 存儲庫中找到。 ## 俄羅斯方塊 俄羅斯方塊游戲是有史以來最受歡迎的計算機游戲之一。 原始游戲是由俄羅斯程序員 Alexey Pajitnov 于 1985 年設計和編程的。此后,幾乎所有版本的幾乎所有計算機平臺上都可以使用俄羅斯方塊。 甚至我的手機都有俄羅斯方塊游戲的修改版。 俄羅斯方塊被稱為下降塊益智游戲。 在這個游戲中,我們有七個不同的形狀,稱為`tetrominoes`。 S 形,Z 形,T 形,L 形,線形,鏡像 L 形和正方形。 這些形狀中的每一個都形成有四個正方形。 形狀從板上掉下來。 俄羅斯方塊游戲的目的是移動和旋轉形狀,以便它們盡可能地適合。 如果我們設法形成一行,則該行將被破壞并得分。 我們玩俄羅斯方塊游戲,直到達到頂峰。 ![Tetrominoes](https://img.kancloud.cn/2b/7a/2b7a874cd2ec9a34c259d3dd686809e9_328x132.jpg) 圖:Tetrominoes ## 開發 使用 Swing 繪畫 API 繪制四方塊。 我們使用`java.util.Timer`創建游戲周期。 形狀以正方形為單位移動(而不是逐個像素移動)。 從數學上講,游戲中的棋盤是一個簡單的數字列表。 游戲啟動后立即開始。 我們可以通過按`p`鍵暫停游戲。 空格鍵將把俄羅斯方塊放在底部。 `d`鍵將片段向下一行。 (它可以用來加快下降速度。)游戲以恒定速度運行,沒有實現加速。 分數是我們已刪除的行數。 `com/zetcode/Shape.java` ```java package com.zetcode; import java.util.Random; public class Shape { protected enum Tetrominoe { NoShape, ZShape, SShape, LineShape, TShape, SquareShape, LShape, MirroredLShape } private Tetrominoe pieceShape; private int[][] coords; public Shape() { coords = new int[4][2]; setShape(Tetrominoe.NoShape); } void setShape(Tetrominoe shape) { int[][][] coordsTable = new int[][][]{ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}, {{0, -1}, {0, 0}, {1, 0}, {1, 1}}, {{0, -1}, {0, 0}, {0, 1}, {0, 2}}, {{-1, 0}, {0, 0}, {1, 0}, {0, 1}}, {{0, 0}, {1, 0}, {0, 1}, {1, 1}}, {{-1, -1}, {0, -1}, {0, 0}, {0, 1}}, {{1, -1}, {0, -1}, {0, 0}, {0, 1}} }; for (int i = 0; i < 4; i++) { System.arraycopy(coordsTable[shape.ordinal()], 0, coords, 0, 4); } pieceShape = shape; } private void setX(int index, int x) { coords[index][0] = x; } private void setY(int index, int y) { coords[index][1] = y; } int x(int index) { return coords[index][0]; } int y(int index) { return coords[index][1]; } Tetrominoe getShape() { return pieceShape; } void setRandomShape() { var r = new Random(); int x = Math.abs(r.nextInt()) % 7 + 1; Tetrominoe[] values = Tetrominoe.values(); setShape(values[x]); } public int minX() { int m = coords[0][0]; for (int i = 0; i < 4; i++) { m = Math.min(m, coords[i][0]); } return m; } int minY() { int m = coords[0][1]; for (int i = 0; i < 4; i++) { m = Math.min(m, coords[i][1]); } return m; } Shape rotateLeft() { if (pieceShape == Tetrominoe.SquareShape) { return this; } var result = new Shape(); result.pieceShape = pieceShape; for (int i = 0; i < 4; i++) { result.setX(i, y(i)); result.setY(i, -x(i)); } return result; } Shape rotateRight() { if (pieceShape == Tetrominoe.SquareShape) { return this; } var result = new Shape(); result.pieceShape = pieceShape; for (int i = 0; i < 4; i++) { result.setX(i, -y(i)); result.setY(i, x(i)); } return result; } } ``` `Shape`類提供有關俄羅斯方塊的信息。 ```java protected enum Tetrominoe { NoShape, ZShape, SShape, LineShape, TShape, SquareShape, LShape, MirroredLShape } ``` `Tetrominoe`枚舉包含七個俄羅斯方塊形狀名稱和一個稱為`NoShape`的空形狀。 ```java coords = new int[4][2]; setShape(Tetrominoe.NoShape); ``` `coords`數組保存俄羅斯方塊的實際坐標。 ```java int[][][] coordsTable = new int[][][]{ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, {{0, -1}, {0, 0}, {-1, 0}, {-1, 1}}, {{0, -1}, {0, 0}, {1, 0}, {1, 1}}, {{0, -1}, {0, 0}, {0, 1}, {0, 2}}, {{-1, 0}, {0, 0}, {1, 0}, {0, 1}}, {{0, 0}, {1, 0}, {0, 1}, {1, 1}}, {{-1, -1}, {0, -1}, {0, 0}, {0, 1}}, {{1, -1}, {0, -1}, {0, 0}, {0, 1}} }; ``` `coordsTable`數組保存俄羅斯方塊的所有可能的坐標值。 這是一個模板,所有作品都從該模板中獲得其坐標值。 ```java for (int i = 0; i < 4; i++) { System.arraycopy(coordsTable[shape.ordinal()], 0, coords, 0, 4); } ``` 我們將來自`coordsTable`的一行坐標值放入俄羅斯方塊的`coords`數組中。 注意`ordinal()`方法的用法。 在 C++ 中,枚舉類型本質上是整數。 與 C++ 不同,Java 枚舉是完整類,`ordinal()`方法返回枚舉類型在枚舉對象中的當前位置。 下圖將幫助您更多地了解坐標值。 `coords`數組保存俄羅斯方塊的坐標。 例如,數字(-1、1),(-1、0),(0、0)和(0,-1)表示旋轉的 S 形。 下圖說明了形狀。 ![Coordinates](https://img.kancloud.cn/5c/0b/5c0bbb2ed04c22b46915ea1ef803ce4d_272x230.jpg) 圖:坐標 ```java Shape rotateLeft() { if (pieceShape == Tetrominoe.SquareShape) { return this; } var result = new Shape(); result.pieceShape = pieceShape; for (int i = 0; i < 4; i++) { result.setX(i, y(i)); result.setY(i, -x(i)); } return result; } ``` 此代碼將一塊向左旋轉。 正方形不必旋轉。 這就是為什么我們只是將引用返回到當前對象。 查看上一張圖像將有助于理解旋轉。 `com/zetcode/Board.java` ```java package com.zetcode; import com.zetcode.Shape.Tetrominoe; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.Timer; import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; public class Board extends JPanel { private final int BOARD_WIDTH = 10; private final int BOARD_HEIGHT = 22; private final int PERIOD_INTERVAL = 300; private Timer timer; private boolean isFallingFinished = false; private boolean isPaused = false; private int numLinesRemoved = 0; private int curX = 0; private int curY = 0; private JLabel statusbar; private Shape curPiece; private Tetrominoe[] board; public Board(Tetris parent) { initBoard(parent); } private void initBoard(Tetris parent) { setFocusable(true); statusbar = parent.getStatusBar(); addKeyListener(new TAdapter()); } private int squareWidth() { return (int) getSize().getWidth() / BOARD_WIDTH; } private int squareHeight() { return (int) getSize().getHeight() / BOARD_HEIGHT; } private Tetrominoe shapeAt(int x, int y) { return board[(y * BOARD_WIDTH) + x]; } void start() { curPiece = new Shape(); board = new Tetrominoe[BOARD_WIDTH * BOARD_HEIGHT]; clearBoard(); newPiece(); timer = new Timer(PERIOD_INTERVAL, new GameCycle()); timer.start(); } private void pause() { isPaused = !isPaused; if (isPaused) { statusbar.setText("paused"); } else { statusbar.setText(String.valueOf(numLinesRemoved)); } repaint(); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); doDrawing(g); } private void doDrawing(Graphics g) { var size = getSize(); int boardTop = (int) size.getHeight() - BOARD_HEIGHT * squareHeight(); for (int i = 0; i < BOARD_HEIGHT; i++) { for (int j = 0; j < BOARD_WIDTH; j++) { Tetrominoe shape = shapeAt(j, BOARD_HEIGHT - i - 1); if (shape != Tetrominoe.NoShape) { drawSquare(g, j * squareWidth(), boardTop + i * squareHeight(), shape); } } } if (curPiece.getShape() != Tetrominoe.NoShape) { for (int i = 0; i < 4; i++) { int x = curX + curPiece.x(i); int y = curY - curPiece.y(i); drawSquare(g, x * squareWidth(), boardTop + (BOARD_HEIGHT - y - 1) * squareHeight(), curPiece.getShape()); } } } private void dropDown() { int newY = curY; while (newY > 0) { if (!tryMove(curPiece, curX, newY - 1)) { break; } newY--; } pieceDropped(); } private void oneLineDown() { if (!tryMove(curPiece, curX, curY - 1)) { pieceDropped(); } } private void clearBoard() { for (int i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; i++) { board[i] = Tetrominoe.NoShape; } } private void pieceDropped() { for (int i = 0; i < 4; i++) { int x = curX + curPiece.x(i); int y = curY - curPiece.y(i); board[(y * BOARD_WIDTH) + x] = curPiece.getShape(); } removeFullLines(); if (!isFallingFinished) { newPiece(); } } private void newPiece() { curPiece.setRandomShape(); curX = BOARD_WIDTH / 2 + 1; curY = BOARD_HEIGHT - 1 + curPiece.minY(); if (!tryMove(curPiece, curX, curY)) { curPiece.setShape(Tetrominoe.NoShape); timer.stop(); var msg = String.format("Game over. Score: %d", numLinesRemoved); statusbar.setText(msg); } } private boolean tryMove(Shape newPiece, int newX, int newY) { for (int i = 0; i < 4; i++) { int x = newX + newPiece.x(i); int y = newY - newPiece.y(i); if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { return false; } if (shapeAt(x, y) != Tetrominoe.NoShape) { return false; } } curPiece = newPiece; curX = newX; curY = newY; repaint(); return true; } private void removeFullLines() { int numFullLines = 0; for (int i = BOARD_HEIGHT - 1; i >= 0; i--) { boolean lineIsFull = true; for (int j = 0; j < BOARD_WIDTH; j++) { if (shapeAt(j, i) == Tetrominoe.NoShape) { lineIsFull = false; break; } } if (lineIsFull) { numFullLines++; for (int k = i; k < BOARD_HEIGHT - 1; k++) { for (int j = 0; j < BOARD_WIDTH; j++) { board[(k * BOARD_WIDTH) + j] = shapeAt(j, k + 1); } } } } if (numFullLines > 0) { numLinesRemoved += numFullLines; statusbar.setText(String.valueOf(numLinesRemoved)); isFallingFinished = true; curPiece.setShape(Tetrominoe.NoShape); } } private void drawSquare(Graphics g, int x, int y, Tetrominoe shape) { Color colors[] = {new Color(0, 0, 0), new Color(204, 102, 102), new Color(102, 204, 102), new Color(102, 102, 204), new Color(204, 204, 102), new Color(204, 102, 204), new Color(102, 204, 204), new Color(218, 170, 0) }; var color = colors[shape.ordinal()]; g.setColor(color); g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2); g.setColor(color.brighter()); g.drawLine(x, y + squareHeight() - 1, x, y); g.drawLine(x, y, x + squareWidth() - 1, y); g.setColor(color.darker()); g.drawLine(x + 1, y + squareHeight() - 1, x + squareWidth() - 1, y + squareHeight() - 1); g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1, x + squareWidth() - 1, y + 1); } private class GameCycle implements ActionListener { @Override public void actionPerformed(ActionEvent e) { doGameCycle(); } } private void doGameCycle() { update(); repaint(); } private void update() { if (isPaused) { return; } if (isFallingFinished) { isFallingFinished = false; newPiece(); } else { oneLineDown(); } } class TAdapter extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { if (curPiece.getShape() == Tetrominoe.NoShape) { return; } int keycode = e.getKeyCode(); // Java 12 switch expressions switch (keycode) { case KeyEvent.VK_P -> pause(); case KeyEvent.VK_LEFT -> tryMove(curPiece, curX - 1, curY); case KeyEvent.VK_RIGHT -> tryMove(curPiece, curX + 1, curY); case KeyEvent.VK_DOWN -> tryMove(curPiece.rotateRight(), curX, curY); case KeyEvent.VK_UP -> tryMove(curPiece.rotateLeft(), curX, curY); case KeyEvent.VK_SPACE -> dropDown(); case KeyEvent.VK_D -> oneLineDown(); } } } } ``` 最后,我們有`Board.java`文件。 這是游戲邏輯所在的位置。 ```java private final int BOARD_WIDTH = 10; private final int BOARD_HEIGHT = 22; private final int PERIOD_INTERVAL = 300; ``` 我們有四個常數。 `BOARD_WIDTH`和`BOARD_HEIGHT`定義了電路板的大小。 `PERIOD_INTERVAL`常數定義游戲的速度。 ```java ... private boolean isFallingFinished = false; private boolean isStarted = false; private boolean isPaused = false; private int numLinesRemoved = 0; private int curX = 0; private int curY = 0; ... ``` 一些重要的變量被初始化。 `isFallingFinished`確定俄羅斯方塊形狀是否已經完成下降,然后我們需要創建一個新形狀。 `isStarted`用于檢查游戲是否已經開始。 同樣,`isPaused`用于檢查游戲是否暫停。 `numLinesRemoved`計算到目前為止我們已刪除的行數。 `curX`和`curY`確定下降的俄羅斯方塊形狀的實際位置。 ```java private int squareWidth() { return (int) getSize().getWidth() / BOARD_WIDTH; } private int squareHeight() { return (int) getSize().getHeight() / BOARD_HEIGHT; } ``` 這些線確定單個 Tetrominoe 正方形的寬度和高度。 ```java private Tetrominoe shapeAt(int x, int y) { return board[(y * BOARD_WIDTH) + x]; } ``` 我們確定給定坐標處的形狀。 形狀存儲在`board`數組中。 ```java void start() { curPiece = new Shape(); board = new Tetrominoe[BOARD_WIDTH * BOARD_HEIGHT]; ... ``` 我們創建一個新的當前形狀和一個新的板。 ```java clearBoard(); newPiece(); ``` 清理板并初始化新的下降片。 ```java timer = new Timer(PERIOD_INTERVAL, new GameCycle()); timer.start(); ``` 我們創建一個計時器。 計時器以`PERIOD_INTERVAL`間隔執行,從而創建游戲周期。 ```java private void pause() { isPaused = !isPaused; if (isPaused) { statusbar.setText("paused"); } else { statusbar.setText(String.valueOf(numLinesRemoved)); } repaint(); } ``` `pause()`方法暫停或繼續游戲。 游戲暫停后,我們會在狀態欄中顯示`paused`消息。 在`doDrawing()`方法內部,我們在板上繪制了所有對象。 這幅畫有兩個步驟。 ```java for (int i = 0; i < BOARD_HEIGHT; i++) { for (int j = 0; j < BOARD_WIDTH; j++) { Tetrominoe shape = shapeAt(j, BOARD_HEIGHT - i - 1); if (shape != Tetrominoe.NoShape) { drawSquare(g, j * squareWidth(), boardTop + i * squareHeight(), shape); } } } ``` 在第一步中,我們繪制掉落到板底部的所有形狀或形狀的其余部分。 所有正方形都記在板數組中。 我們使用`shapeAt()`方法訪問它。 ```java if (curPiece.getShape() != Tetrominoe.NoShape) { for (int i = 0; i < 4; i++) { int x = curX + curPiece.x(i); int y = curY - curPiece.y(i); drawSquare(g, x * squareWidth(), boardTop + (BOARD_HEIGHT - y - 1) * squareHeight(), curPiece.getShape()); } } ``` 在第二步中,我們繪制實際的下降部分。 ```java private void dropDown() { int newY = curY; while (newY > 0) { if (!tryMove(curPiece, curX, newY - 1)) { break; } newY--; } pieceDropped(); } ``` 如果按`Space`鍵,則該片段將落到底部。 我們只是簡單地嘗試將一塊下降到另一條俄羅斯方塊下降的底部或頂部。 當俄羅斯方塊結束下降時,將調用`pieceDropped()`。 ```java private void oneLineDown() { if (!tryMove(curPiece, curX, curY - 1)) { pieceDropped(); } } ``` 在`oneLineDown()`方法中,我們嘗試將下降片向下移動一行,直到完全下降。 ```java private void clearBoard() { for (int i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; i++) { board[i] = Tetrominoe.NoShape; } } ``` `clearBoard()`方法用空的`Tetrominoe.NoShape`填充電路板。 稍后將其用于碰撞檢測。 ```java private void pieceDropped() { for (int i = 0; i < 4; i++) { int x = curX + curPiece.x(i); int y = curY - curPiece.y(i); board[(y * BOARD_WIDTH) + x] = curPiece.getShape(); } removeFullLines(); if (!isFallingFinished) { newPiece(); } } ``` `pieceDropped()`方法將下降的片段放入`board`數組。 棋盤再次保持了所有碎片的正方形和已經落下的碎片的剩余部分。 當一塊完成落下時,就該檢查我們是否可以從板上去除一些線了。 這是`removeFullLines()`方法的工作。 然后,我們創建一個新作品,或更準確地說,我們嘗試創建一個新作品。 ```java private void newPiece() { curPiece.setRandomShape(); curX = BOARD_WIDTH / 2 + 1; curY = BOARD_HEIGHT - 1 + curPiece.minY(); if (!tryMove(curPiece, curX, curY)) { curPiece.setShape(Tetrominoe.NoShape); timer.stop(); var msg = String.format("Game over. Score: %d", numLinesRemoved); statusbar.setText(msg); } } ``` `newPiece()`方法創建一個新的俄羅斯方塊。 作品獲得了新的隨機形狀。 然后,我們計算初始`curX`和`curY`值。 如果我們不能移動到初始位置,則游戲結束了,我們結束了。 計時器停止運行,我們在狀態欄上顯示`Game over`包含分數的字符串。 ```java private boolean tryMove(Shape newPiece, int newX, int newY) { for (int i = 0; i < 4; i++) { int x = newX + newPiece.x(i); int y = newY - newPiece.y(i); if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { return false; } if (shapeAt(x, y) != Tetrominoe.NoShape) { return false; } } curPiece = newPiece; curX = newX; curY = newY; repaint(); return true; } ``` `tryMove()`方法嘗試移動俄羅斯方塊。 如果該方法已到達板邊界或與已經跌落的俄羅斯方塊碎片相鄰,則返回`false`。 ```java private void removeFullLines() { int numFullLines = 0; for (int i = BOARD_HEIGHT - 1; i >= 0; i--) { boolean lineIsFull = true; for (int j = 0; j < BOARD_WIDTH; j++) { if (shapeAt(j, i) == Tetrominoe.NoShape) { lineIsFull = false; break; } } if (lineIsFull) { numFullLines++; for (int k = i; k < BOARD_HEIGHT - 1; k++) { for (int j = 0; j < BOARD_WIDTH; j++) { board[(k * BOARD_WIDTH) + j] = shapeAt(j, k + 1); } } } } if (numFullLines > 0) { numLinesRemoved += numFullLines; statusbar.setText(String.valueOf(numLinesRemoved)); isFallingFinished = true; curPiece.setShape(Tetrominoe.NoShape); } } ``` 在`removeFullLines()`方法內部,我們檢查板上的所有行中是否有完整的行。 如果至少有一條實線,則將其刪除。 找到整條線后,我們增加計數器。 我們將整行上方的所有行向下移動一行。 這樣我們就破壞了整個生產線。 注意,在我們的俄羅斯方塊游戲中,我們使用了所謂的天真重力。 這意味著正方形可能會漂浮在空白間隙上方。 ```java private void drawSquare(Graphics g, int x, int y, Tetrominoe shape) { Color colors[] = {new Color(0, 0, 0), new Color(204, 102, 102), new Color(102, 204, 102), new Color(102, 102, 204), new Color(204, 204, 102), new Color(204, 102, 204), new Color(102, 204, 204), new Color(218, 170, 0) }; var color = colors[shape.ordinal()]; g.setColor(color); g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2); g.setColor(color.brighter()); g.drawLine(x, y + squareHeight() - 1, x, y); g.drawLine(x, y, x + squareWidth() - 1, y); g.setColor(color.darker()); g.drawLine(x + 1, y + squareHeight() - 1, x + squareWidth() - 1, y + squareHeight() - 1); g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1, x + squareWidth() - 1, y + 1); } ``` 每個俄羅斯方塊都有四個正方形。 每個正方形都使用`drawSquare()`方法繪制。 俄羅斯方塊有不同的顏色。 正方形的左側和頂部以較亮的顏色繪制。 類似地,底部和右側用較深的顏色繪制。 這是為了模擬 3D 邊緣。 ```java private class GameCycle implements ActionListener { @Override public void actionPerformed(ActionEvent e) { doGameCycle(); } } ``` 在`GameCycle`中,我們調用`doGameCycle()`方法,以創建游戲周期。 ```java private void doGameCycle() { update(); repaint(); } ``` 游戲分為游戲周期。 每個循環都會抽水游戲并重畫棋盤。 ```java private void update() { if (isPaused) { return; } if (isFallingFinished) { isFallingFinished = false; newPiece(); } else { oneLineDown(); } } ``` `update()`代表游戲的第一步。 下降的零件向下一行,或者如果前一個零件已完成下降,則創建新的零件。 ```java private class TAdapter extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { ... ``` 游戲由光標鍵控制。 我們在`KeyAdapter`中檢查關鍵事件。 ```java int keycode = e.getKeyCode(); ``` 我們使用`getKeyCode()`方法獲得按鍵代碼。 ```java // Java 12 switch expressions switch (keycode) { case KeyEvent.VK_P -> pause(); case KeyEvent.VK_LEFT -> tryMove(curPiece, curX - 1, curY); case KeyEvent.VK_RIGHT -> tryMove(curPiece, curX + 1, curY); case KeyEvent.VK_DOWN -> tryMove(curPiece.rotateRight(), curX, curY); case KeyEvent.VK_UP -> tryMove(curPiece.rotateLeft(), curX, curY); case KeyEvent.VK_SPACE -> dropDown(); case KeyEvent.VK_D -> oneLineDown(); } ``` 使用 Java 12 `switch`表達式,我們將鍵事件綁定到方法。 例如,使用 `Space` 鍵,我們將下降的俄羅斯方塊放下。 `com/zetcode/Tetris.java` ```java package com.zetcode; import java.awt.BorderLayout; import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JLabel; /* Java Tetris game clone Author: Jan Bodnar Website: http://zetcode.com */ public class Tetris extends JFrame { private JLabel statusbar; public Tetris() { initUI(); } private void initUI() { statusbar = new JLabel(" 0"); add(statusbar, BorderLayout.SOUTH); var board = new Board(this); add(board); board.start(); setTitle("Tetris"); setSize(200, 400); setDefaultCloseOperation(EXIT_ON_CLOSE); setLocationRelativeTo(null); } JLabel getStatusBar() { return statusbar; } public static void main(String[] args) { EventQueue.invokeLater(() -> { var game = new Tetris(); game.setVisible(true); }); } } ``` 在`Tetris.java`文件中,我們設置了游戲。 我們創建一個玩游戲的棋盤。 我們創建一個狀態欄。 ```java statusbar = new JLabel(" 0"); add(statusbar, BorderLayout.SOUTH); ``` 分數顯示在位于板底部的標簽中。 ```java var board = new Board(this); add(board); board.start(); ``` 棋盤被創建并添加到容器中。 `start()`方法啟動俄羅斯方塊游戲。 ![Tetris](https://img.kancloud.cn/f9/16/f9161375bb4d694f52d356516cfdde10_200x400.jpg) 圖:俄羅斯方塊 這是俄羅斯方塊游戲。 {% endraw %}
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看