├── Board.java ├── MainMenu.java ├── README.md ├── Shape.java ├── TAdapter.java ├── Tetris.java ├── Tetris ├── Board.java ├── MainMenu.java ├── Shape.java ├── TAdapter.java ├── Tetris.java ├── kethop.png ├── muiten.png ├── music1.mp3 ├── thayThong.jpg └── wasd.png ├── ThuanTheBadLuckCoder ├── kethop.png ├── muiten.png ├── music1.mp3 ├── thayThong.jpg └── wasd.png /Board.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Font; 6 | import java.awt.Graphics; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | 10 | 11 | //import javax.swing.JButton; 12 | import javax.swing.JLabel; 13 | import javax.swing.JPanel; 14 | import javax.swing.Timer; 15 | 16 | import Tetris.Shape.Tetrominoes; 17 | 18 | public class Board extends JPanel implements ActionListener { 19 | //checked 20 | private Tetris tetris; 21 | private final int BoardWidth = 10; 22 | private final int BoardHeight = 22; 23 | private Timer timer; 24 | private boolean isFallingFinished = false; 25 | private boolean isStarted = false; 26 | boolean isPaused = false; 27 | private boolean gameOver= false; 28 | private int numLinesRemoved = 0; 29 | private int curX = 0; 30 | private int curY = 0; 31 | private JLabel statusbar; 32 | private Shape curPiece; 33 | private Tetrominoes[] board; 34 | //checked 35 | public Board(Tetris parent, JLabel statusbar, TAdapter adapter) { 36 | initBoard(parent, statusbar, adapter); 37 | } 38 | 39 | public boolean getIsStarted(){ 40 | return isStarted; 41 | } 42 | 43 | //checked 44 | private void initBoard(Tetris parent, JLabel statusbar, TAdapter adapter) { 45 | tetris = parent; 46 | setFocusable(true); 47 | curPiece = new Shape(); 48 | timer = new Timer(400, this); 49 | timer.start(); 50 | 51 | this.statusbar = statusbar; 52 | statusbar.setFont(new Font("Serif", Font.PLAIN, 30)); 53 | board = new Tetrominoes[BoardWidth * BoardHeight]; 54 | clearBoard(); 55 | addListener(adapter); 56 | } 57 | 58 | public void addListener(TAdapter adapter){ 59 | adapter.addBoard(this); 60 | addKeyListener(adapter); 61 | } 62 | 63 | 64 | 65 | //checked 66 | @Override 67 | public void actionPerformed(ActionEvent e) { 68 | if (!isPaused) { 69 | if (isFallingFinished) { 70 | isFallingFinished = false; 71 | newPiece(); 72 | } else { 73 | oneLineDown(); 74 | } 75 | } 76 | 77 | } 78 | //checked 79 | private int squareWidth() { 80 | return (int) getSize().getWidth() / BoardWidth; 81 | } 82 | private int squareHeight() { 83 | return (int) getSize().getHeight() / BoardHeight; 84 | } 85 | private Tetrominoes shapeAt(int x, int y) { 86 | return board[(y * BoardWidth) + x]; 87 | } 88 | 89 | //check 90 | public void start() { 91 | 92 | if (isPaused) 93 | return; 94 | 95 | isStarted = true; 96 | isFallingFinished = false; 97 | numLinesRemoved = 0; 98 | clearBoard(); 99 | 100 | newPiece(); 101 | timer.start(); 102 | } 103 | 104 | //checked 105 | public void pause() { 106 | 107 | if (!isStarted) 108 | return; 109 | 110 | isPaused = !isPaused; 111 | 112 | if (isPaused) { 113 | timer.stop(); 114 | statusbar.setText("paused"); 115 | } else { 116 | 117 | timer.start(); 118 | statusbar.setText(String.valueOf(numLinesRemoved)); 119 | } 120 | 121 | repaint(); 122 | } 123 | 124 | //checked 125 | private void doDrawing(Graphics g) { 126 | Dimension size = getSize(); 127 | int boardTop = (int) size.getHeight() - BoardHeight * squareHeight(); 128 | 129 | for (int i = 0; i < BoardHeight; ++i) { 130 | 131 | for (int j = 0; j < BoardWidth; ++j) { 132 | 133 | Tetrominoes shape = shapeAt(j, BoardHeight - i - 1); 134 | 135 | if (shape != Tetrominoes.NoShape) 136 | drawSquare(g, 0 + j * squareWidth(), 137 | boardTop + i * squareHeight(), shape); 138 | } 139 | } 140 | 141 | if (curPiece.getShape() != Tetrominoes.NoShape) { 142 | 143 | for (int i = 0; i < 4; ++i) { 144 | int x = curX + curPiece.x(i); 145 | int y = curY - curPiece.y(i); 146 | drawSquare(g, 0 + x * squareWidth(), boardTop + (BoardHeight - y - 1) * squareHeight(), curPiece.getShape()); 147 | } 148 | } 149 | 150 | 151 | } 152 | //checked 153 | @Override 154 | public void paintComponent(Graphics g) { 155 | super.paintComponent(g); 156 | doDrawing(g); 157 | } 158 | //checked 159 | public void dropDown() { 160 | if(!isPaused) { 161 | int newY = curY; 162 | while (newY > 0) { 163 | 164 | if (!tryMove(0, -1)) 165 | break; 166 | --newY; 167 | 168 | } 169 | pieceDropped(); 170 | } 171 | 172 | 173 | } 174 | //checked 175 | public void oneLineDown() { 176 | 177 | if (!tryMove(0, -1)) 178 | pieceDropped(); 179 | 180 | 181 | } 182 | 183 | //checked 184 | private void clearBoard() { 185 | 186 | for (int i = 0; i < BoardHeight * BoardWidth; ++i) 187 | board[i] = Tetrominoes.NoShape; 188 | 189 | 190 | } 191 | 192 | //checked 193 | private void pieceDropped() { 194 | if (!isPaused) { 195 | for (int i = 0; i < 4; ++i) { 196 | 197 | int x = curX + curPiece.x(i); 198 | int y = curY - curPiece.y(i); 199 | board[(y * BoardWidth) + x] = curPiece.getShape(); 200 | } 201 | 202 | removeFullLines(); 203 | 204 | if (!isFallingFinished) 205 | newPiece(); 206 | } 207 | 208 | } 209 | //checked 210 | private void newPiece() { 211 | if (!isPaused) { 212 | curPiece.setRandomShape(); 213 | curX = BoardWidth / 2 - 1; 214 | curY = BoardHeight - 1 + curPiece.minY(); 215 | 216 | if (!tryMove(0, 0)) { 217 | 218 | curPiece.setShape(Tetrominoes.NoShape); 219 | timer.stop(); 220 | isStarted = false; 221 | statusbar.setText("Game Over!!!"); 222 | if(!gameOver) 223 | tetris.gameOver(); 224 | gameOver = true; 225 | } 226 | } 227 | 228 | } 229 | //checked 230 | public boolean tryMove(int difX, int difY) { 231 | if(!isPaused) { 232 | for (int i = 0; i < 4; ++i) { 233 | int x = curX + difX + curPiece.x(i); 234 | int y = curY + difY - curPiece.y(i); 235 | 236 | 237 | if (x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight) 238 | return false; 239 | 240 | if (shapeAt(x, y) != Tetrominoes.NoShape) 241 | return false; 242 | } 243 | 244 | curX += difX; 245 | curY += difY; 246 | 247 | repaint(); 248 | 249 | 250 | } 251 | 252 | return true; 253 | } 254 | 255 | public boolean rotateLeft() { 256 | Shape temp = new Shape(curPiece); 257 | curPiece = curPiece.rotateLeft(); 258 | if(tryMove(0, 0)) 259 | return true; 260 | else{ 261 | curPiece = temp; 262 | return false; 263 | } 264 | } 265 | //checked 266 | private void removeFullLines() { 267 | if (!isPaused) { 268 | int numFullLines = 0; 269 | 270 | for (int i = BoardHeight - 1; i >= 0; --i) { 271 | boolean lineIsFull = true; 272 | 273 | for (int j = 0; j < BoardWidth; ++j) { 274 | if (shapeAt(j, i) == Tetrominoes.NoShape) { 275 | lineIsFull = false; 276 | break; 277 | } 278 | } 279 | 280 | if (lineIsFull) { 281 | ++numFullLines; 282 | for (int k = i; k < BoardHeight - 1; ++k) { 283 | for (int j = 0; j < BoardWidth; ++j) 284 | board[(k * BoardWidth) + j] = shapeAt(j, k + 1); 285 | } 286 | } 287 | } 288 | if (numFullLines > 0) { 289 | 290 | numLinesRemoved += numFullLines; 291 | statusbar.setText(String.valueOf(numLinesRemoved)); 292 | isFallingFinished = true; 293 | curPiece.setShape(Tetrominoes.NoShape); 294 | repaint(); 295 | } 296 | } 297 | 298 | } 299 | //checked 300 | private void drawSquare(Graphics g, int x, int y, Tetrominoes shape) { 301 | 302 | Color colors[] = { 303 | //NoShape 304 | new Color(0, 0, 0), 305 | //ZShape 306 | new Color(204, 102, 102), 307 | //oZ 308 | new Color(102, 204, 102), 309 | //L 310 | //I 311 | new Color(204, 102, 204), 312 | //T 313 | new Color(218, 170, 0), 314 | //Square 315 | new Color(102, 204, 204), 316 | new Color(102, 102, 204), 317 | //oL 318 | new Color(204, 204, 102) 319 | }; 320 | 321 | Color color = colors[shape.ordinal()]; 322 | 323 | g.setColor(color); 324 | g.fillRect(x + 4, y + 4, squareWidth() - 4, squareHeight() - 4); 325 | 326 | g.setColor(color.brighter()); 327 | g.drawLine(x, y + squareHeight() - 2, x, y); 328 | g.drawLine(x, y, x + squareWidth() - 2, y); 329 | 330 | g.setColor(color.darker()); 331 | g.drawLine(x + 2, y + squareHeight() - 2, 332 | x + squareWidth() - 2, y + squareHeight() - 2); 333 | g.drawLine(x + squareWidth() - 2, y + squareHeight() - 2, 334 | x + squareWidth() - 2, y + 2); 335 | 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /MainMenu.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import java.awt.Graphics; 8 | import java.awt.image.BufferedImage; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import javax.imageio.ImageIO; 14 | import javax.swing.JPanel; 15 | 16 | 17 | 18 | public class MainMenu extends JFrame { 19 | JButton onePlayer = new JButton("1 Player"); 20 | JButton twoPlayers = new JButton("2 Players"); 21 | JButton howToPlay = new JButton("How To Play"); 22 | JButton exit = new JButton("Exit"); 23 | JButton exit1 = new JButton("Back"); 24 | JFrame MainMenuFr = new JFrame("Tetris Time!"); 25 | int a = -1; 26 | ActionEvent e; 27 | Tetris game; 28 | 29 | 30 | public MainMenu() { 31 | addButtons(); 32 | } 33 | 34 | public void addButtons() { 35 | onePlayer.setBounds(95, 50, 200, 80); 36 | twoPlayers.setBounds(95, 150, 200, 80); 37 | howToPlay.setBounds(95, 250, 200, 80); 38 | exit.setBounds(125, 400, 120, 40); 39 | 40 | MainMenuFr.add(onePlayer); 41 | MainMenuFr.add(twoPlayers); 42 | MainMenuFr.add(howToPlay); 43 | MainMenuFr.add(exit); 44 | try { 45 | ImageIcon image = new ImageIcon(getClass().getResource("thayThong.jpg")); 46 | JLabel displayField = new JLabel(image); 47 | MainMenuFr.add(displayField); 48 | } catch(Exception e) { 49 | System.out.println("Image cannot be found"); 50 | } 51 | MainMenuFr.setSize(400, 500); 52 | //MainMenuFr.setLayout(null); 53 | MainMenuFr.setResizable(false); 54 | MainMenuFr.setVisible(true); 55 | MainMenuFr.setLocationRelativeTo(null); 56 | 57 | 58 | onePlayer.addActionListener(new ActionListener() { 59 | 60 | @Override 61 | public void actionPerformed(ActionEvent e) { 62 | a = 1; 63 | //System.out.println(getA()); 64 | game = new Tetris(a); 65 | MainMenuFr.setVisible(false); 66 | game.setVisible(true); 67 | //System.exit(0); 68 | } 69 | 70 | }); 71 | 72 | twoPlayers.addActionListener(new ActionListener() { 73 | @Override 74 | public void actionPerformed(ActionEvent e) { 75 | a = 2; 76 | //System.out.println(getA()); 77 | game = new Tetris(a); 78 | MainMenuFr.setVisible(false); 79 | game.setVisible(true); 80 | //System.exit(0); 81 | } 82 | }); 83 | 84 | howToPlay.addActionListener(new ActionListener() { 85 | @Override 86 | public void actionPerformed(ActionEvent e) { 87 | JFrame howToPlayButton = new JFrame(); 88 | howToPlayButton.setSize(1000, 800); 89 | howToPlayButton.setVisible(true); 90 | howToPlayButton.setResizable(false); 91 | howToPlayButton.setLocationRelativeTo(null); 92 | 93 | exit1.setBounds(425, 700, 160, 40); 94 | howToPlayButton.add(exit1); 95 | 96 | 97 | try { 98 | ImageIcon image = new ImageIcon(getClass().getResource("kethop.png")); 99 | JLabel displayField = new JLabel(image); 100 | howToPlayButton.add(displayField); 101 | } catch (Exception i) { 102 | //System.out.println("Image cannot be found"); 103 | } 104 | 105 | 106 | exit1.addActionListener(new ActionListener() { 107 | @Override 108 | public void actionPerformed(ActionEvent e) { 109 | // TODO Auto-generated method stub 110 | //System.out.println("0"); 111 | howToPlayButton.setVisible(false); 112 | 113 | } 114 | }); 115 | } 116 | }); 117 | 118 | exit.addActionListener(new ActionListener() { 119 | @Override 120 | public void actionPerformed(ActionEvent e) { 121 | // TODO Auto-generated method stub 122 | //System.out.println("0"); 123 | System.exit(0); 124 | 125 | } 126 | }); 127 | } 128 | 129 | public int getA() { 130 | return a; 131 | } 132 | } 133 | 134 | 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Tetris Game

2 | 3 |
4 |

Overview

5 | 6 | This is a simple implementation of the classic Tetris game developed as a part of the Object-Oriented Programming (OOP) course. The project is built using Java and focuses on providing a highly customizable experience for players. All Tetris blocks (Tetrominoes) are fully coded, allowing for easy customization and a more user-friendly gaming experience. 7 | 8 |

Features

9 | 15 | 16 |

Installation

17 | To run this game on your local machine, follow these steps: 18 | 19 | 1. Clone the repository: 20 | git clone https://github.com/yourusername/tetris-game.git 21 | 22 | 2. Navigate to the project directory: 23 | cd tetris-game 24 | 25 | 3. Compile the project: 26 | javac -d bin src/*.java 27 | 28 | 4. Run the game: 29 | java -cp bin Main 30 | 31 |

How to Play

32 | 38 | 39 | 40 |

Customization

41 | To customize the Tetrominoes: 42 | 43 | 1. Open the Tetromino.java file in the src directory. 44 | 45 | 2. Modify the shapes, colors, or other properties as desired. 46 | 47 | 3. Recompile and run the game to see your changes in action. 48 | 49 |

Contributing

50 | If you'd like to contribute to the project, feel free to fork the repository and submit a pull request. 51 | 52 | Any contributions, such as bug fixes, feature enhancements, or documentation improvements, are welcome! 53 | 54 |

Contact

55 | If you have any questions or feedback, feel free to reach out: 56 | 57 | Email: dtthuan.contact@gmail.com 58 | 59 | GitHub: dtr_thuann 60 | -------------------------------------------------------------------------------- /Shape.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | import java.util.Random; 3 | 4 | public class Shape { 5 | 6 | public enum Tetrominoes { NoShape, ZShape, oZShape, IShape, 7 | TShape, SquareShape, LShape, oLShape }; 8 | 9 | private Tetrominoes pieceShape; 10 | private int coords[][] = new int[4][2]; 11 | private int[][][] coordsTable; 12 | 13 | 14 | public Shape() { 15 | setShape(Tetrominoes.NoShape); 16 | } 17 | 18 | public Shape(Shape shape) { 19 | this.pieceShape = shape.pieceShape; 20 | for (int i = 0; i < 4; ++i) { 21 | this.setX(i, shape.x(i)); 22 | this.setY(i, shape.y(i)); 23 | } 24 | } 25 | 26 | public void setShape(Tetrominoes shape) { 27 | 28 | coordsTable = new int[][][] { 29 | //NoShape1 30 | {{0,0}, {0,0}, {0,0}, {0,0}}, 31 | //ZShape2 32 | {{0,1}, {0,0}, {1,0}, {1,-1}}, 33 | //oZShape3 34 | {{0,1}, {0,0}, {-1, 0}, {-1,-1}}, 35 | //IShape6 36 | //{{2,0}, {1,0}, {0,0}, {-1,0}}, 37 | {{ 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 }}, 38 | //TShape7 39 | {{1,0}, {0,0}, {0,1}, {-1,0}}, 40 | //SquareShape 41 | {{1,0}, {1,1}, {0,0}, {0,1}}, 42 | //LShape4 43 | {{1,-1}, {0,-1}, {0,0}, {0,1}}, 44 | //oLShape5 45 | {{0,-1}, {0,0}, {0,1}, {-1,-1}} 46 | }; 47 | 48 | for (int i = 0; i < 4 ; i++) { 49 | 50 | for (int j = 0; j < 2; ++j) { 51 | 52 | coords[i][j] = coordsTable[shape.ordinal()][i][j]; 53 | } 54 | } 55 | 56 | pieceShape = shape; 57 | } 58 | 59 | 60 | 61 | 62 | public void setRandomShape() { 63 | 64 | Random r = new Random(); 65 | int x = Math.abs(r.nextInt()) % 7 + 1; 66 | Tetrominoes[] values = Tetrominoes.values(); 67 | setShape(values[x]); 68 | } 69 | 70 | public int minX() { 71 | 72 | int m = coords[0][0]; 73 | 74 | for (int i = 0; i < 4; i++) { 75 | 76 | m = Math.min(m, coords[i][0]); 77 | } 78 | 79 | return m; 80 | } 81 | 82 | 83 | public int minY() { 84 | 85 | int m = coords[0][1]; 86 | 87 | for (int i = 0; i < 4; i++) { 88 | 89 | m = Math.min(m, coords[i][1]); 90 | } 91 | 92 | return m; 93 | } 94 | 95 | public int x(int index) { 96 | return coords[index][0]; 97 | } 98 | public int y(int index) { 99 | return coords[index][1]; 100 | } 101 | public Tetrominoes getShape() { 102 | return pieceShape; 103 | } 104 | 105 | private void setX(int index, int x) { 106 | coords[index][0] = x; 107 | } 108 | 109 | private void setY(int index, int y) { 110 | coords[index][1] = y; 111 | } 112 | 113 | public Shape rotateLeft() { 114 | if (pieceShape == Tetrominoes.SquareShape) { 115 | return this; 116 | } 117 | 118 | Shape result = new Shape(); 119 | result.pieceShape = pieceShape; 120 | for (int i = 0; i < 4; ++i) { 121 | result.setX(i, y(i)); 122 | result.setY(i, -x(i)); 123 | } 124 | return result; 125 | } 126 | 127 | /*public Shape rotateRight() { 128 | 129 | if (pieceShape == Tetrominoes.SquareShape) { 130 | return this; 131 | } 132 | 133 | else if (pieceShape == Tetrominoes.IShape) { 134 | 135 | } 136 | 137 | else { 138 | Shape result = new Shape(); 139 | result.pieceShape = pieceShape; 140 | 141 | for (int i = 0; i < 4; ++i) { 142 | 143 | result.setX(i, -y(i)); 144 | result.setY(i, x(i)); 145 | } 146 | 147 | return result; 148 | } 149 | 150 | } */ 151 | 152 | 153 | } 154 | -------------------------------------------------------------------------------- /TAdapter.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.event.*; 4 | import java.util.ArrayList; 5 | 6 | public class TAdapter extends KeyAdapter { 7 | ArrayList boards = new ArrayList<>(); 8 | 9 | public void addBoard(Board board) { 10 | boards.add(board); 11 | } 12 | 13 | @Override 14 | public void keyPressed(KeyEvent e) { 15 | /* 16 | if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) { 17 | return; 18 | }*/ 19 | 20 | int keycode = e.getKeyCode(); 21 | 22 | if (keycode == 'p' || keycode == 'P') { 23 | for(Board board : boards) 24 | board.pause(); 25 | return; 26 | } 27 | 28 | 29 | /*if (isPaused) 30 | return;*/ 31 | 32 | switch (boards.size()) { 33 | case 2: 34 | controlPlayer2(keycode); 35 | case 1: 36 | controlPlayer1(keycode); 37 | break; 38 | default: 39 | break; 40 | } 41 | } 42 | 43 | private void controlPlayer1(int keycode){ 44 | Board board = boards.get(0); 45 | 46 | switch (keycode) { 47 | case KeyEvent.VK_LEFT: 48 | board.tryMove(-1, 0); 49 | break; 50 | 51 | case KeyEvent.VK_RIGHT: 52 | board.tryMove(1, 0); 53 | break; 54 | 55 | case KeyEvent.VK_UP: 56 | board.rotateLeft(); 57 | break; 58 | 59 | case KeyEvent.VK_DOWN: 60 | board.oneLineDown(); 61 | break; 62 | case KeyEvent.VK_L: 63 | board.dropDown(); 64 | break; 65 | case KeyEvent.VK_P: 66 | board.pause(); 67 | break; 68 | } 69 | 70 | 71 | } 72 | 73 | private void controlPlayer2(int keycode){ 74 | Board board = boards.get(1); 75 | switch (keycode) { 76 | case KeyEvent.VK_A: 77 | board.tryMove(-1, 0); 78 | break; 79 | 80 | case KeyEvent.VK_D: 81 | board.tryMove(1, 0); 82 | break; 83 | 84 | case KeyEvent.VK_W: 85 | board.rotateLeft(); 86 | break; 87 | 88 | case KeyEvent.VK_S: 89 | board.oneLineDown(); 90 | break; 91 | 92 | case KeyEvent.VK_G: 93 | board.dropDown(); 94 | break; 95 | case KeyEvent.VK_P: 96 | board.pause(); 97 | break; 98 | } 99 | 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Tetris.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.*; 4 | 5 | import javax.sound.sampled.AudioSystem; 6 | import javax.swing.*; 7 | 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | 11 | 12 | import java.io.FileInputStream; 13 | import java.io.FileNotFoundException; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.Scanner; 18 | 19 | import javax.sound.sampled.*; 20 | 21 | public class Tetris extends JFrame { 22 | private JLabel statusbar; 23 | private JLabel statusbar1; 24 | static JPanel mainPanel = new JPanel(); 25 | JButton playAgain; 26 | int player; 27 | static MainMenu a = new MainMenu(); 28 | 29 | public static void main(String[] args) throws UnsupportedAudioFileException, IOException, LineUnavailableException { 30 | 31 | /* SwingUtilities.invokeLater(new Runnable() { 32 | 33 | @Override 34 | public void run() { 35 | while (a.getA() != -1) { 36 | int numberOfPlayer = a.getA(); 37 | a.MainMenuFr.setVisible(false); 38 | if (numberOfPlayer == 1 || numberOfPlayer == 2) { 39 | Tetris game = new Tetris(numberOfPlayer); 40 | game.setVisible(true); 41 | System.out.print("da chay"); 42 | 43 | } 44 | else { 45 | System.out.print("khong chay"); 46 | } 47 | } 48 | 49 | } 50 | }); */ 51 | 52 | } 53 | 54 | public void playSound() {{ 55 | new Thread(new Runnable() { 56 | public void run() { 57 | try { 58 | AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("music.wav").getAbsoluteFile()); 59 | Clip clip = AudioSystem.getClip(); 60 | clip.open(audioInputStream); 61 | clip.start(); 62 | } catch(Exception ex) { 63 | System.out.println("Error with playing sound."); 64 | ex.printStackTrace(); 65 | } 66 | } 67 | }).start(); 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | public Tetris(int numberOfPlayer) { 75 | playSound(); 76 | mainPanel = new JPanel(); 77 | player = numberOfPlayer; 78 | playAgain = new JButton("Back To Menu?"); 79 | playAgain.addActionListener(new ActionListener() { 80 | @Override 81 | public void actionPerformed(ActionEvent e) { 82 | setVisible(false); 83 | a.MainMenuFr.setVisible(true); 84 | } 85 | }); 86 | add(playAgain); 87 | playAgain.setVisible(false); 88 | if (numberOfPlayer == 1) { 89 | //System.out.println("so 1"); 90 | initUI(); 91 | } 92 | else if (numberOfPlayer == 2) { 93 | //System.out.println("so 2"); 94 | initUI2Players(); 95 | } 96 | 97 | } 98 | 99 | int count = 0; 100 | public void gameOver() { 101 | count++; 102 | if(player == 1) { 103 | playAgain.setBounds(110 ,650, 180, 60); 104 | playAgain.setVisible(true); 105 | } else { 106 | if(count == 2){ 107 | playAgain.setBounds(310 ,650, 180, 60); 108 | playAgain.setVisible(true); 109 | } 110 | } 111 | } 112 | 113 | private void initUI2Players() { 114 | TAdapter adapter = new TAdapter(); 115 | 116 | statusbar = new JLabel(" 0"); 117 | 118 | 119 | Board board = new Board(this, statusbar, adapter); 120 | board.add(statusbar, BorderLayout.PAGE_END); 121 | board.start(); 122 | 123 | statusbar1 = new JLabel(" 0"); 124 | 125 | 126 | Board board1 = new Board(this, statusbar1, adapter); 127 | 128 | board1.add(statusbar1, BorderLayout.PAGE_END); 129 | mainPanel.add(board1); 130 | mainPanel.add(board); 131 | board1.start(); 132 | 133 | 134 | 135 | mainPanel.setLayout(new GridLayout(0, 2,5,2)); 136 | mainPanel.setSize(800,800); 137 | setBackground(Color.black); 138 | 139 | add(mainPanel); 140 | 141 | setResizable(false); 142 | 143 | setSize(800, 800); 144 | setTitle("Tetris"); 145 | setDefaultCloseOperation(EXIT_ON_CLOSE); 146 | setLocationRelativeTo(null); 147 | setResizable(false); 148 | 149 | //set mau nen 150 | board.setBackground(Color.DARK_GRAY); 151 | //board1.setBackground(Color.white); 152 | 153 | 154 | 155 | } 156 | 157 | public void initUI() { 158 | TAdapter adapter = new TAdapter(); 159 | 160 | statusbar = new JLabel(" 0"); 161 | add(statusbar, BorderLayout.SOUTH); 162 | Board board = new Board(this, statusbar, adapter); 163 | add(board); 164 | board.start(); 165 | 166 | setSize(400, 800); 167 | setTitle("Tetris"); 168 | setDefaultCloseOperation(EXIT_ON_CLOSE); 169 | setLocationRelativeTo(null); 170 | setResizable(false); 171 | 172 | //set mau nen 173 | board.setBackground(Color.black); 174 | } 175 | 176 | 177 | // public JLabel getStatusBar() { 178 | 179 | // return statusbar; 180 | // } 181 | } -------------------------------------------------------------------------------- /Tetris/Board.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Graphics; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | 9 | 10 | //import javax.swing.JButton; 11 | import javax.swing.JLabel; 12 | import javax.swing.JPanel; 13 | import javax.swing.Timer; 14 | 15 | import Tetris.Shape.Tetrominoes; 16 | 17 | public class Board extends JPanel implements ActionListener { 18 | //checked 19 | private Tetris tetris; 20 | private final int BoardWidth = 10; 21 | private final int BoardHeight = 22; 22 | private Timer timer; 23 | private boolean isFallingFinished = false; 24 | private boolean isStarted = false; 25 | boolean isPaused = false; 26 | private boolean gameOver= false; 27 | private int numLinesRemoved = 0; 28 | private int curX = 0; 29 | private int curY = 0; 30 | private JLabel statusbar; 31 | private Shape curPiece; 32 | private Tetrominoes[] board; 33 | //checked 34 | public Board(Tetris parent, JLabel statusbar, TAdapter adapter) { 35 | initBoard(parent, statusbar, adapter); 36 | } 37 | 38 | public boolean getIsStarted(){ 39 | return isStarted; 40 | } 41 | 42 | //checked 43 | private void initBoard(Tetris parent, JLabel statusbar, TAdapter adapter) { 44 | tetris = parent; 45 | setFocusable(true); 46 | curPiece = new Shape(); 47 | timer = new Timer(400, this); 48 | timer.start(); 49 | 50 | this.statusbar = statusbar; 51 | board = new Tetrominoes[BoardWidth * BoardHeight]; 52 | clearBoard(); 53 | addListener(adapter); 54 | } 55 | 56 | public void addListener(TAdapter adapter){ 57 | adapter.addBoard(this); 58 | addKeyListener(adapter); 59 | } 60 | 61 | 62 | 63 | //checked 64 | @Override 65 | public void actionPerformed(ActionEvent e) { 66 | if (!isPaused) { 67 | if (isFallingFinished) { 68 | isFallingFinished = false; 69 | newPiece(); 70 | } else { 71 | oneLineDown(); 72 | } 73 | } 74 | 75 | } 76 | //checked 77 | private int squareWidth() { 78 | return (int) getSize().getWidth() / BoardWidth; 79 | } 80 | private int squareHeight() { 81 | return (int) getSize().getHeight() / BoardHeight; 82 | } 83 | private Tetrominoes shapeAt(int x, int y) { 84 | return board[(y * BoardWidth) + x]; 85 | } 86 | 87 | //check 88 | public void start() { 89 | 90 | if (isPaused) 91 | return; 92 | 93 | isStarted = true; 94 | isFallingFinished = false; 95 | numLinesRemoved = 0; 96 | clearBoard(); 97 | 98 | newPiece(); 99 | timer.start(); 100 | } 101 | 102 | //checked 103 | public void pause() { 104 | 105 | if (!isStarted) 106 | return; 107 | 108 | isPaused = !isPaused; 109 | 110 | if (isPaused) { 111 | 112 | timer.stop(); 113 | statusbar.setText("paused"); 114 | } else { 115 | 116 | timer.start(); 117 | statusbar.setText(String.valueOf(numLinesRemoved)); 118 | } 119 | 120 | repaint(); 121 | } 122 | 123 | //checked 124 | private void doDrawing(Graphics g) { 125 | if (!isPaused) { 126 | Dimension size = getSize(); 127 | int boardTop = (int) size.getHeight() - BoardHeight * squareHeight(); 128 | 129 | for (int i = 0; i < BoardHeight; ++i) { 130 | 131 | for (int j = 0; j < BoardWidth; ++j) { 132 | 133 | Tetrominoes shape = shapeAt(j, BoardHeight - i - 1); 134 | 135 | if (shape != Tetrominoes.NoShape) 136 | drawSquare(g, 0 + j * squareWidth(), 137 | boardTop + i * squareHeight(), shape); 138 | } 139 | } 140 | 141 | if (curPiece.getShape() != Tetrominoes.NoShape) { 142 | 143 | for (int i = 0; i < 4; ++i) { 144 | int x = curX + curPiece.x(i); 145 | int y = curY - curPiece.y(i); 146 | drawSquare(g, 0 + x * squareWidth(), boardTop + (BoardHeight - y - 1) * squareHeight(), curPiece.getShape()); 147 | } 148 | } 149 | } 150 | 151 | } 152 | //checked 153 | @Override 154 | public void paintComponent(Graphics g) { 155 | super.paintComponent(g); 156 | doDrawing(g); 157 | } 158 | //checked 159 | public void dropDown() { 160 | if(!isPaused) { 161 | int newY = curY; 162 | while (newY > 0) { 163 | 164 | if (!tryMove(0, -1)) 165 | break; 166 | --newY; 167 | 168 | } 169 | pieceDropped(); 170 | } 171 | 172 | 173 | } 174 | //checked 175 | public void oneLineDown() { 176 | if (!isPaused) { 177 | if (!tryMove(0, -1)) 178 | pieceDropped(); 179 | } 180 | 181 | } 182 | 183 | //checked 184 | private void clearBoard() { 185 | if (!isPaused) { 186 | for (int i = 0; i < BoardHeight * BoardWidth; ++i) 187 | board[i] = Tetrominoes.NoShape; 188 | } 189 | 190 | } 191 | 192 | //checked 193 | private void pieceDropped() { 194 | if (!isPaused) { 195 | for (int i = 0; i < 4; ++i) { 196 | 197 | int x = curX + curPiece.x(i); 198 | int y = curY - curPiece.y(i); 199 | board[(y * BoardWidth) + x] = curPiece.getShape(); 200 | } 201 | 202 | removeFullLines(); 203 | 204 | if (!isFallingFinished) 205 | newPiece(); 206 | } 207 | 208 | } 209 | //checked 210 | private void newPiece() { 211 | if (!isPaused) { 212 | curPiece.setRandomShape(); 213 | curX = BoardWidth / 2 - 1; 214 | curY = BoardHeight - 1 + curPiece.minY(); 215 | 216 | if (!tryMove(0, 0)) { 217 | 218 | curPiece.setShape(Tetrominoes.NoShape); 219 | timer.stop(); 220 | isStarted = false; 221 | statusbar.setText("Game Over!!!"); 222 | if(!gameOver) 223 | tetris.gameOver(); 224 | gameOver = true; 225 | } 226 | } 227 | 228 | } 229 | //checked 230 | public boolean tryMove(int difX, int difY) { 231 | if(!isPaused) { 232 | for (int i = 0; i < 4; ++i) { 233 | int x = curX + difX + curPiece.x(i); 234 | int y = curY + difY - curPiece.y(i); 235 | 236 | 237 | if (x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight) 238 | return false; 239 | 240 | if (shapeAt(x, y) != Tetrominoes.NoShape) 241 | return false; 242 | } 243 | 244 | curX += difX; 245 | curY += difY; 246 | 247 | repaint(); 248 | 249 | 250 | } 251 | 252 | return true; 253 | } 254 | 255 | public boolean rotateLeft() { 256 | Shape temp = new Shape(curPiece); 257 | curPiece = curPiece.rotateLeft(); 258 | if(tryMove(0, 0)) 259 | return true; 260 | else{ 261 | curPiece = temp; 262 | return false; 263 | } 264 | } 265 | //checked 266 | private void removeFullLines() { 267 | if (!isPaused) { 268 | int numFullLines = 0; 269 | 270 | for (int i = BoardHeight - 1; i >= 0; --i) { 271 | boolean lineIsFull = true; 272 | 273 | for (int j = 0; j < BoardWidth; ++j) { 274 | if (shapeAt(j, i) == Tetrominoes.NoShape) { 275 | lineIsFull = false; 276 | break; 277 | } 278 | } 279 | 280 | if (lineIsFull) { 281 | ++numFullLines; 282 | for (int k = i; k < BoardHeight - 1; ++k) { 283 | for (int j = 0; j < BoardWidth; ++j) 284 | board[(k * BoardWidth) + j] = shapeAt(j, k + 1); 285 | } 286 | } 287 | } 288 | if (numFullLines > 0) { 289 | 290 | numLinesRemoved += numFullLines; 291 | statusbar.setText(String.valueOf(numLinesRemoved)); 292 | isFallingFinished = true; 293 | curPiece.setShape(Tetrominoes.NoShape); 294 | repaint(); 295 | } 296 | } 297 | 298 | } 299 | //checked 300 | private void drawSquare(Graphics g, int x, int y, Tetrominoes shape) { 301 | 302 | Color colors[] = { 303 | //NoShape 304 | new Color(0, 0, 0), 305 | //ZShape 306 | new Color(204, 102, 102), 307 | //oZ 308 | new Color(102, 204, 102), 309 | //L 310 | //I 311 | new Color(204, 102, 204), 312 | //T 313 | new Color(218, 170, 0), 314 | //Square 315 | new Color(102, 204, 204), 316 | new Color(102, 102, 204), 317 | //oL 318 | new Color(204, 204, 102) 319 | }; 320 | 321 | Color color = colors[shape.ordinal()]; 322 | 323 | g.setColor(color); 324 | g.fillRect(x + 4, y + 4, squareWidth() - 4, squareHeight() - 4); 325 | 326 | g.setColor(color.brighter()); 327 | g.drawLine(x, y + squareHeight() - 2, x, y); 328 | g.drawLine(x, y, x + squareWidth() - 2, y); 329 | 330 | g.setColor(color.darker()); 331 | g.drawLine(x + 2, y + squareHeight() - 2, 332 | x + squareWidth() - 2, y + squareHeight() - 2); 333 | g.drawLine(x + squareWidth() - 2, y + squareHeight() - 2, 334 | x + squareWidth() - 2, y + 2); 335 | 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /Tetris/MainMenu.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.ActionEvent; 6 | import java.awt.event.ActionListener; 7 | import java.awt.Graphics; 8 | import java.awt.image.BufferedImage; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | import javax.imageio.ImageIO; 14 | import javax.swing.JPanel; 15 | 16 | 17 | 18 | public class MainMenu extends JFrame { 19 | JButton onePlayer = new JButton("1 Player"); 20 | JButton twoPlayers = new JButton("2 Players"); 21 | JButton howToPlay = new JButton("How To Play"); 22 | JButton exit = new JButton("Exit"); 23 | JButton exit1 = new JButton("Back"); 24 | JFrame MainMenuFr = new JFrame("Tetris Time!"); 25 | int a = -1; 26 | ActionEvent e; 27 | Tetris game; 28 | 29 | 30 | public MainMenu() { 31 | addButtons(); 32 | } 33 | 34 | public void addButtons() { 35 | onePlayer.setBounds(95, 50, 200, 80); 36 | twoPlayers.setBounds(95, 150, 200, 80); 37 | howToPlay.setBounds(95, 250, 200, 80); 38 | exit.setBounds(125, 400, 120, 40); 39 | 40 | MainMenuFr.add(onePlayer); 41 | MainMenuFr.add(twoPlayers); 42 | MainMenuFr.add(howToPlay); 43 | MainMenuFr.add(exit); 44 | try { 45 | ImageIcon image = new ImageIcon(getClass().getResource("thayThong.jpg")); 46 | JLabel displayField = new JLabel(image); 47 | MainMenuFr.add(displayField); 48 | } catch(Exception e) { 49 | System.out.println("Image cannot be found"); 50 | } 51 | MainMenuFr.setSize(400, 500); 52 | //MainMenuFr.setLayout(null); 53 | MainMenuFr.setResizable(false); 54 | MainMenuFr.setVisible(true); 55 | MainMenuFr.setLocationRelativeTo(null); 56 | 57 | 58 | onePlayer.addActionListener(new ActionListener() { 59 | 60 | @Override 61 | public void actionPerformed(ActionEvent e) { 62 | a = 1; 63 | //System.out.println(getA()); 64 | game = new Tetris(a); 65 | MainMenuFr.setVisible(false); 66 | game.setVisible(true); 67 | //System.exit(0); 68 | } 69 | 70 | }); 71 | 72 | twoPlayers.addActionListener(new ActionListener() { 73 | @Override 74 | public void actionPerformed(ActionEvent e) { 75 | a = 2; 76 | //System.out.println(getA()); 77 | game = new Tetris(a); 78 | MainMenuFr.setVisible(false); 79 | game.setVisible(true); 80 | //System.exit(0); 81 | } 82 | }); 83 | 84 | howToPlay.addActionListener(new ActionListener() { 85 | @Override 86 | public void actionPerformed(ActionEvent e) { 87 | JFrame howToPlayButton = new JFrame(); 88 | howToPlayButton.setSize(1000, 800); 89 | howToPlayButton.setVisible(true); 90 | howToPlayButton.setResizable(false); 91 | howToPlayButton.setLocationRelativeTo(null); 92 | 93 | exit1.setBounds(425, 700, 160, 40); 94 | howToPlayButton.add(exit1); 95 | 96 | 97 | try { 98 | ImageIcon image = new ImageIcon(getClass().getResource("kethop.png")); 99 | JLabel displayField = new JLabel(image); 100 | howToPlayButton.add(displayField); 101 | } catch (Exception i) { 102 | //System.out.println("Image cannot be found"); 103 | } 104 | 105 | 106 | exit1.addActionListener(new ActionListener() { 107 | @Override 108 | public void actionPerformed(ActionEvent e) { 109 | // TODO Auto-generated method stub 110 | //System.out.println("0"); 111 | howToPlayButton.setVisible(false); 112 | 113 | } 114 | }); 115 | } 116 | }); 117 | 118 | exit.addActionListener(new ActionListener() { 119 | @Override 120 | public void actionPerformed(ActionEvent e) { 121 | // TODO Auto-generated method stub 122 | //System.out.println("0"); 123 | System.exit(0); 124 | 125 | } 126 | }); 127 | } 128 | 129 | public int getA() { 130 | return a; 131 | } 132 | } 133 | 134 | 135 | -------------------------------------------------------------------------------- /Tetris/Shape.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | import java.util.Random; 3 | 4 | public class Shape { 5 | 6 | public enum Tetrominoes { NoShape, ZShape, oZShape, IShape, 7 | TShape, SquareShape, LShape, oLShape }; 8 | 9 | private Tetrominoes pieceShape; 10 | private int coords[][] = new int[4][2]; 11 | private int[][][] coordsTable; 12 | 13 | 14 | public Shape() { 15 | setShape(Tetrominoes.NoShape); 16 | } 17 | 18 | public Shape(Shape shape) { 19 | this.pieceShape = shape.pieceShape; 20 | for (int i = 0; i < 4; ++i) { 21 | this.setX(i, shape.x(i)); 22 | this.setY(i, shape.y(i)); 23 | } 24 | } 25 | 26 | public void setShape(Tetrominoes shape) { 27 | 28 | coordsTable = new int[][][] { 29 | //NoShape1 30 | {{0,0}, {0,0}, {0,0}, {0,0}}, 31 | //ZShape2 32 | {{0,1}, {0,0}, {1,0}, {1,-1}}, 33 | //oZShape3 34 | {{0,1}, {0,0}, {-1, 0}, {-1,-1}}, 35 | //IShape6 36 | //{{2,0}, {1,0}, {0,0}, {-1,0}}, 37 | {{ 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 }}, 38 | //TShape7 39 | {{1,0}, {0,0}, {0,1}, {-1,0}}, 40 | //SquareShape 41 | {{1,0}, {1,1}, {0,0}, {0,1}}, 42 | //LShape4 43 | {{1,-1}, {0,-1}, {0,0}, {0,1}}, 44 | //oLShape5 45 | {{0,-1}, {0,0}, {0,1}, {-1,-1}} 46 | }; 47 | 48 | for (int i = 0; i < 4 ; i++) { 49 | 50 | for (int j = 0; j < 2; ++j) { 51 | 52 | coords[i][j] = coordsTable[shape.ordinal()][i][j]; 53 | } 54 | } 55 | 56 | pieceShape = shape; 57 | } 58 | 59 | 60 | 61 | 62 | public void setRandomShape() { 63 | 64 | Random r = new Random(); 65 | int x = Math.abs(r.nextInt()) % 7 + 1; 66 | Tetrominoes[] values = Tetrominoes.values(); 67 | setShape(values[x]); 68 | } 69 | 70 | public int minX() { 71 | 72 | int m = coords[0][0]; 73 | 74 | for (int i=0; i < 4; i++) { 75 | 76 | m = Math.min(m, coords[i][0]); 77 | } 78 | 79 | return m; 80 | } 81 | 82 | 83 | public int minY() { 84 | 85 | int m = coords[0][1]; 86 | 87 | for (int i=0; i < 4; i++) { 88 | 89 | m = Math.min(m, coords[i][1]); 90 | } 91 | 92 | return m; 93 | } 94 | 95 | public int x(int index) { 96 | return coords[index][0]; 97 | } 98 | public int y(int index) { 99 | return coords[index][1]; 100 | } 101 | public Tetrominoes getShape() { 102 | return pieceShape; 103 | } 104 | 105 | private void setX(int index, int x) { 106 | coords[index][0] = x; 107 | } 108 | 109 | private void setY(int index, int y) { 110 | coords[index][1] = y; 111 | } 112 | 113 | public Shape rotateLeft() { 114 | if (pieceShape == Tetrominoes.SquareShape) { 115 | return this; 116 | } 117 | 118 | Shape result = new Shape(); 119 | result.pieceShape = pieceShape; 120 | for (int i = 0; i < 4; ++i) { 121 | result.setX(i, y(i)); 122 | result.setY(i, -x(i)); 123 | } 124 | return result; 125 | } 126 | 127 | /*public Shape rotateRight() { 128 | 129 | if (pieceShape == Tetrominoes.SquareShape) { 130 | return this; 131 | } 132 | 133 | else if (pieceShape == Tetrominoes.IShape) { 134 | 135 | } 136 | 137 | else { 138 | Shape result = new Shape(); 139 | result.pieceShape = pieceShape; 140 | 141 | for (int i = 0; i < 4; ++i) { 142 | 143 | result.setX(i, -y(i)); 144 | result.setY(i, x(i)); 145 | } 146 | 147 | return result; 148 | } 149 | 150 | } */ 151 | 152 | 153 | } 154 | -------------------------------------------------------------------------------- /Tetris/TAdapter.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.event.*; 4 | import java.util.ArrayList; 5 | 6 | public class TAdapter extends KeyAdapter { 7 | ArrayList boards = new ArrayList<>(); 8 | 9 | public void addBoard(Board board) { 10 | boards.add(board); 11 | } 12 | 13 | @Override 14 | public void keyPressed(KeyEvent e) { 15 | /* 16 | if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) { 17 | return; 18 | }*/ 19 | 20 | int keycode = e.getKeyCode(); 21 | 22 | if (keycode == 'p' || keycode == 'P') { 23 | for(Board board : boards) 24 | board.pause(); 25 | return; 26 | } 27 | 28 | 29 | /*if (isPaused) 30 | return;*/ 31 | 32 | switch (boards.size()) { 33 | case 2: 34 | controlPlayer2(keycode); 35 | case 1: 36 | controlPlayer1(keycode); 37 | break; 38 | default: 39 | break; 40 | } 41 | } 42 | 43 | private void controlPlayer1(int keycode){ 44 | Board board = boards.get(0); 45 | if (!board.isPaused) { 46 | switch (keycode) { 47 | case KeyEvent.VK_LEFT: 48 | board.tryMove(-1, 0); 49 | break; 50 | 51 | case KeyEvent.VK_RIGHT: 52 | board.tryMove(1, 0); 53 | break; 54 | 55 | case KeyEvent.VK_UP: 56 | board.rotateLeft(); 57 | break; 58 | 59 | case KeyEvent.VK_DOWN: 60 | board.oneLineDown(); 61 | break; 62 | case KeyEvent.VK_L: 63 | board.dropDown(); 64 | break; 65 | case KeyEvent.VK_P: 66 | board.pause(); 67 | break; 68 | } 69 | } 70 | 71 | } 72 | 73 | private void controlPlayer2(int keycode){ 74 | Board board = boards.get(1); 75 | if (!board.isPaused) { 76 | switch (keycode) { 77 | case KeyEvent.VK_A: 78 | board.tryMove(-1, 0); 79 | break; 80 | 81 | case KeyEvent.VK_D: 82 | board.tryMove(1, 0); 83 | break; 84 | 85 | case KeyEvent.VK_W: 86 | board.rotateLeft(); 87 | break; 88 | 89 | case KeyEvent.VK_S: 90 | board.oneLineDown(); 91 | break; 92 | 93 | case KeyEvent.VK_G: 94 | board.dropDown(); 95 | break; 96 | } 97 | } 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tetris/Tetris.java: -------------------------------------------------------------------------------- 1 | package Tetris; 2 | 3 | import java.awt.*; 4 | 5 | import javax.sound.sampled.AudioSystem; 6 | import javax.swing.*; 7 | 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | 11 | 12 | import java.io.FileInputStream; 13 | import java.io.FileNotFoundException; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.Scanner; 18 | 19 | import javax.sound.sampled.*; 20 | 21 | public class Tetris extends JFrame { 22 | private JLabel statusbar; 23 | private JLabel statusbar1; 24 | static JPanel mainPanel = new JPanel(); 25 | JButton playAgain; 26 | int player; 27 | static MainMenu a = new MainMenu(); 28 | 29 | public static void main(String[] args) throws UnsupportedAudioFileException, IOException, LineUnavailableException { 30 | 31 | /* SwingUtilities.invokeLater(new Runnable() { 32 | 33 | @Override 34 | public void run() { 35 | while (a.getA() != -1) { 36 | int numberOfPlayer = a.getA(); 37 | a.MainMenuFr.setVisible(false); 38 | if (numberOfPlayer == 1 || numberOfPlayer == 2) { 39 | Tetris game = new Tetris(numberOfPlayer); 40 | game.setVisible(true); 41 | System.out.print("da chay"); 42 | 43 | } 44 | else { 45 | System.out.print("khong chay"); 46 | } 47 | } 48 | 49 | } 50 | }); */ 51 | 52 | } 53 | 54 | public void playSound() {{ 55 | new Thread(new Runnable() { 56 | public void run() { 57 | try { 58 | AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("music.wav").getAbsoluteFile()); 59 | Clip clip = AudioSystem.getClip(); 60 | clip.open(audioInputStream); 61 | clip.start(); 62 | } catch(Exception ex) { 63 | System.out.println("Error with playing sound."); 64 | ex.printStackTrace(); 65 | } 66 | } 67 | }).start(); 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | public Tetris(int numberOfPlayer) { 75 | playSound(); 76 | mainPanel = new JPanel(); 77 | player = numberOfPlayer; 78 | playAgain = new JButton("Back To Menu?"); 79 | playAgain.addActionListener(new ActionListener() { 80 | @Override 81 | public void actionPerformed(ActionEvent e) { 82 | setVisible(false); 83 | a.MainMenuFr.setVisible(true); 84 | } 85 | }); 86 | add(playAgain); 87 | playAgain.setVisible(false); 88 | if (numberOfPlayer == 1) { 89 | //System.out.println("so 1"); 90 | initUI(); 91 | } 92 | else if (numberOfPlayer == 2) { 93 | //System.out.println("so 2"); 94 | initUI2Players(); 95 | } 96 | 97 | } 98 | 99 | int count = 0; 100 | public void gameOver() { 101 | count++; 102 | if(player == 1) { 103 | playAgain.setBounds(110 ,650, 180, 60); 104 | playAgain.setVisible(true); 105 | } else { 106 | if(count == 2){ 107 | playAgain.setBounds(310 ,650, 180, 60); 108 | playAgain.setVisible(true); 109 | } 110 | } 111 | } 112 | 113 | private void initUI2Players() { 114 | TAdapter adapter = new TAdapter(); 115 | 116 | statusbar = new JLabel(" 0"); 117 | 118 | 119 | Board board = new Board(this, statusbar, adapter); 120 | board.add(statusbar, BorderLayout.PAGE_END); 121 | board.start(); 122 | 123 | statusbar1 = new JLabel(" 0"); 124 | 125 | 126 | Board board1 = new Board(this, statusbar1, adapter); 127 | 128 | board1.add(statusbar1, BorderLayout.PAGE_END); 129 | mainPanel.add(board1); 130 | mainPanel.add(board); 131 | board1.start(); 132 | 133 | 134 | 135 | mainPanel.setLayout(new GridLayout(0, 2,5,2)); 136 | mainPanel.setSize(800,800); 137 | setBackground(Color.black); 138 | 139 | add(mainPanel); 140 | 141 | setResizable(false); 142 | 143 | setSize(800, 800); 144 | setTitle("Tetris"); 145 | setDefaultCloseOperation(EXIT_ON_CLOSE); 146 | setLocationRelativeTo(null); 147 | setResizable(false); 148 | 149 | //set mau nen 150 | board.setBackground(Color.DARK_GRAY); 151 | //board1.setBackground(Color.white); 152 | 153 | 154 | 155 | } 156 | 157 | public void initUI() { 158 | TAdapter adapter = new TAdapter(); 159 | 160 | statusbar = new JLabel(" 0"); 161 | add(statusbar, BorderLayout.SOUTH); 162 | Board board = new Board(this, statusbar, adapter); 163 | add(board); 164 | board.start(); 165 | 166 | setSize(400, 800); 167 | setTitle("Tetris"); 168 | setDefaultCloseOperation(EXIT_ON_CLOSE); 169 | setLocationRelativeTo(null); 170 | setResizable(false); 171 | 172 | //set mau nen 173 | board.setBackground(Color.black); 174 | } 175 | 176 | 177 | // public JLabel getStatusBar() { 178 | 179 | // return statusbar; 180 | // } 181 | } -------------------------------------------------------------------------------- /Tetris/kethop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/Tetris/kethop.png -------------------------------------------------------------------------------- /Tetris/muiten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/Tetris/muiten.png -------------------------------------------------------------------------------- /Tetris/music1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/Tetris/music1.mp3 -------------------------------------------------------------------------------- /Tetris/thayThong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/Tetris/thayThong.jpg -------------------------------------------------------------------------------- /Tetris/wasd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/Tetris/wasd.png -------------------------------------------------------------------------------- /ThuanTheBadLuckCoder: -------------------------------------------------------------------------------- 1 | ## 🌐 Socials: 2 | [![Discord](https://img.shields.io/badge/Discord-%237289DA.svg?logo=discord&logoColor=white)](https://discord.gg/silov#0656) [![Facebook](https://img.shields.io/badge/Facebook-%231877F2.svg?logo=Facebook&logoColor=white)](https://facebook.com/dontrnthun) [![Instagram](https://img.shields.io/badge/Instagram-%23E4405F.svg?logo=Instagram&logoColor=white)](https://instagram.com/dtr_thuann) [![LinkedIn](https://img.shields.io/badge/LinkedIn-%230077B5.svg?logo=linkedin&logoColor=white)](https://linkedin.com/in/dtrthuann) [![TikTok](https://img.shields.io/badge/TikTok-%23000000.svg?logo=TikTok&logoColor=white)](https://tiktok.com/@dtrnthun) [![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?logo=Twitter&logoColor=white)](https://twitter.com/dtr_thuann) 3 | 4 | # 💻 Tech Stack: 5 | ![C](https://img.shields.io/badge/c-%2300599C.svg?style=for-the-badge&logo=c&logoColor=white) ![C++](https://img.shields.io/badge/c++-%2300599C.svg?style=for-the-badge&logo=c%2B%2B&logoColor=white) ![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge&logo=css3&logoColor=white) ![Java](https://img.shields.io/badge/java-%23ED8B00.svg?style=for-the-badge&logo=java&logoColor=white) ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) ![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54) ![PHP](https://img.shields.io/badge/php-%23777BB4.svg?style=for-the-badge&logo=php&logoColor=white) ![React Native](https://img.shields.io/badge/react_native-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB) ![Bootstrap](https://img.shields.io/badge/bootstrap-%23563D7C.svg?style=for-the-badge&logo=bootstrap&logoColor=white) ![Laravel](https://img.shields.io/badge/laravel-%23FF2D20.svg?style=for-the-badge&logo=laravel&logoColor=white) ![MySQL](https://img.shields.io/badge/mysql-%2300f.svg?style=for-the-badge&logo=mysql&logoColor=white) ![MicrosoftSQLServer](https://img.shields.io/badge/Microsoft%20SQL%20Sever-CC2927?style=for-the-badge&logo=microsoft%20sql%20server&logoColor=white) ![Adobe After Effects](https://img.shields.io/badge/Adobe%20After%20Effects-9999FF.svg?style=for-the-badge&logo=Adobe%20After%20Effects&logoColor=white) ![Adobe Illustrator](https://img.shields.io/badge/adobeillustrator-%23FF9A00.svg?style=for-the-badge&logo=adobeillustrator&logoColor=white) ![Adobe InDesign](https://img.shields.io/badge/Adobe%20InDesign-49021F?style=for-the-badge&logo=adobeindesign&logoColor=white) ![Adobe Photoshop](https://img.shields.io/badge/adobephotoshop-%2331A8FF.svg?style=for-the-badge&logo=adobephotoshop&logoColor=white) ![Adobe Premiere Pro](https://img.shields.io/badge/Adobe%20Premiere%20Pro-9999FF.svg?style=for-the-badge&logo=Adobe%20Premiere%20Pro&logoColor=white) ![Canva](https://img.shields.io/badge/Canva-%2300C4CC.svg?style=for-the-badge&logo=Canva&logoColor=white) ![Figma](https://img.shields.io/badge/figma-%23F24E1E.svg?style=for-the-badge&logo=figma&logoColor=white) ![Trello](https://img.shields.io/badge/Trello-%23026AA7.svg?style=for-the-badge&logo=Trello&logoColor=white) ![Notion](https://img.shields.io/badge/Notion-%23000000.svg?style=for-the-badge&logo=notion&logoColor=white) ![Portfolio](https://img.shields.io/badge/Portfolio-%23000000.svg?style=for-the-badge&logo=firefox&logoColor=#FF7139) 6 | # 📊 GitHub Stats: 7 | ![](https://github-readme-stats.vercel.app/api?username=ThuanTheBadLuckCoder&theme=dark&hide_border=false&include_all_commits=true&count_private=false)
8 | ![](https://github-readme-streak-stats.herokuapp.com/?user=ThuanTheBadLuckCoder&theme=dark&hide_border=false)
9 | ![](https://github-readme-stats.vercel.app/api/top-langs/?username=ThuanTheBadLuckCoder&theme=dark&hide_border=false&include_all_commits=true&count_private=false&layout=compact) 10 | 11 | ## 🐦 Latest Tweet 12 | [![](https://gtce.itsvg.in/api?username=dtr_thuann)](https://github.com/VishwaGauravIn/github-twitter-card-embed) 13 | 14 | ### ✍️ Random Dev Quote 15 | ![](https://quotes-github-readme.vercel.app/api?type=horizontal&theme=radical) 16 | 17 | ### 🔝 Top Contributed Repo 18 | ![](https://github-contributor-stats.vercel.app/api?username=ThuanTheBadLuckCoder&limit=5&theme=dark&combine_all_yearly_contributions=true) 19 | 20 | --- 21 | [![](https://visitcount.itsvg.in/api?id=ThuanTheBadLuckCoder&icon=0&color=0)](https://visitcount.itsvg.in) 22 | -------------------------------------------------------------------------------- /kethop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/kethop.png -------------------------------------------------------------------------------- /muiten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/muiten.png -------------------------------------------------------------------------------- /music1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/music1.mp3 -------------------------------------------------------------------------------- /thayThong.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/thayThong.jpg -------------------------------------------------------------------------------- /wasd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThuanTheBadLuckCoder/Tetris/d3b2d60f6eae9713b5c4f772178dedc113b13a40/wasd.png --------------------------------------------------------------------------------