• 俄罗斯方块游戏制作


    创建包和文件夹

    1.创建小方块类

    1. package eluosifangkuai;
    2. import java.awt.image.BufferedImage;
    3. import java.util.Objects;
    4. /**
    5. * @author xiaoZhao
    6. * @date 2022/5/7
    7. * @describe
    8. * 小方块类
    9. * 方法: 左移、右移、下落
    10. */
    11. public class Cell {
    12. // 行
    13. private int row;
    14. // 列
    15. private int col;
    16. private BufferedImage image;
    17. public Cell() {
    18. }
    19. public Cell(int row, int col, BufferedImage image) {
    20. this.row = row;
    21. this.col = col;
    22. this.image = image;
    23. }
    24. public int getRow() {
    25. return row;
    26. }
    27. public void setRow(int row) {
    28. this.row = row;
    29. }
    30. public int getCol() {
    31. return col;
    32. }
    33. public void setCol(int col) {
    34. this.col = col;
    35. }
    36. public BufferedImage getImage() {
    37. return image;
    38. }
    39. public void setImage(BufferedImage image) {
    40. this.image = image;
    41. }
    42. @Override
    43. public String toString() {
    44. return "Cell{" +
    45. "row=" + row +
    46. ", col=" + col +
    47. ", image=" + image +
    48. '}';
    49. }
    50. @Override
    51. public boolean equals(Object o) {
    52. if (this == o) {
    53. return true;
    54. }
    55. if (!(o instanceof Cell)) {
    56. return false;
    57. }
    58. Cell cell = (Cell) o;
    59. return getRow() == cell.getRow() &&
    60. getCol() == cell.getCol() &&
    61. Objects.equals(getImage(), cell.getImage());
    62. }
    63. @Override
    64. public int hashCode() {
    65. return Objects.hash(getRow(), getCol(), getImage());
    66. }
    67. //左移动一格
    68. public void left(){
    69. col--;
    70. }
    71. //右移动一格
    72. public void right(){
    73. col++;
    74. }
    75. //下移动一格
    76. public void down(){
    77. row++;
    78. }
    79. }

    2.编写四方格父类

    1. package eluosifangkuai;
    2. import xingzhuang.*;
    3. /**
    4. * @author xiaoZhao
    5. * @date 2022/5/11
    6. * @describe 编写四方格父类
    7. */
    8. public class Tetromino {
    9. public Cell[] cells = new Cell[4];
    10. //旋转的状态
    11. protected State[] states;
    12. //声明旋转次数
    13. protected int count = 10000;
    14. //左移方法
    15. public void moveLeft() {
    16. for (Cell cell : cells) {
    17. cell.left();
    18. }
    19. }
    20. //右移方法
    21. public void moveRight() {
    22. for (Cell cell : cells) {
    23. cell.right();
    24. }
    25. }
    26. //单元格下落
    27. public void moveDrop() {
    28. for (Cell cell : cells) {
    29. cell.down();
    30. }
    31. }
    32. //编写随机生成四方格
    33. public static Tetromino randomOne() {
    34. int num = (int) (Math.random() * 7);
    35. Tetromino tetromino = null;
    36. switch (num) {
    37. case 0:
    38. tetromino = new I();
    39. break;
    40. case 1:
    41. tetromino = new J();
    42. break;
    43. case 2:
    44. tetromino = new L();
    45. break;
    46. case 3:
    47. tetromino = new O();
    48. break;
    49. case 4:
    50. tetromino = new S();
    51. break;
    52. case 5:
    53. tetromino = new T();
    54. break;
    55. case 6:
    56. tetromino = new Z();
    57. break;
    58. }
    59. return tetromino;
    60. }
    61. //顺时针旋转的方法
    62. public void rotateRight() {
    63. if (states.length == 0) {
    64. return;
    65. }
    66. //旋转次数+1
    67. count++;
    68. State s = states[count % states.length];
    69. Cell cell = cells[0];
    70. int row = cell.getRow();
    71. int col = cell.getCol();
    72. cells[1].setRow(row + s.row1);
    73. cells[1].setCol(col + s.col1);
    74. cells[2].setRow(row + s.row2);
    75. cells[2].setCol(col + s.col2);
    76. cells[3].setRow(row + s.row3);
    77. cells[3].setCol(col + s.col3);
    78. }
    79. //逆时针旋转的方法
    80. public void rotateLeft() {
    81. if (states.length == 0) {
    82. return;
    83. }
    84. //旋转次数+1
    85. count--;
    86. State s = states[count % states.length];
    87. Cell cell = cells[0];
    88. int row = cell.getRow();
    89. int col = cell.getCol();
    90. cells[1].setRow(row + s.row1);
    91. cells[1].setCol(col + s.col1);
    92. cells[2].setRow(row + s.row2);
    93. cells[2].setCol(col + s.col2);
    94. cells[3].setRow(row + s.row3);
    95. cells[3].setCol(col + s.col3);
    96. }
    97. //四方格旋转状态的内部类
    98. protected class State {
    99. //存储四方格各元素的位置
    100. int row0, col0, row1, col1, row2, col2, row3, col3;
    101. public State() {
    102. }
    103. public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) {
    104. this.row0 = row0;
    105. this.col0 = col0;
    106. this.row1 = row1;
    107. this.col1 = col1;
    108. this.row2 = row2;
    109. this.col2 = col2;
    110. this.row3 = row3;
    111. this.col3 = col3;
    112. }
    113. public int getRow0() {
    114. return row0;
    115. }
    116. public void setRow0(int row0) {
    117. this.row0 = row0;
    118. }
    119. public int getCol0() {
    120. return col0;
    121. }
    122. public void setCol0(int col0) {
    123. this.col0 = col0;
    124. }
    125. public int getRow1() {
    126. return row1;
    127. }
    128. public void setRow1(int row1) {
    129. this.row1 = row1;
    130. }
    131. public int getCol1() {
    132. return col1;
    133. }
    134. public void setCol1(int col1) {
    135. this.col1 = col1;
    136. }
    137. public int getRow2() {
    138. return row2;
    139. }
    140. public void setRow2(int row2) {
    141. this.row2 = row2;
    142. }
    143. public int getCol2() {
    144. return col2;
    145. }
    146. public void setCol2(int col2) {
    147. this.col2 = col2;
    148. }
    149. public int getRow3() {
    150. return row3;
    151. }
    152. public void setRow3(int row3) {
    153. this.row3 = row3;
    154. }
    155. public int getCol3() {
    156. return col3;
    157. }
    158. public void setCol3(int col3) {
    159. this.col3 = col3;
    160. }
    161. @Override
    162. public String toString() {
    163. return "State{" +
    164. "row0=" + row0 +
    165. ", col0=" + col0 +
    166. ", row1=" + row1 +
    167. ", col1=" + col1 +
    168. ", row2=" + row2 +
    169. ", col2=" + col2 +
    170. ", row3=" + row3 +
    171. ", col3=" + col3 +
    172. '}';
    173. }
    174. }
    175. }

    3.编写字母

    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class I extends Tetromino {
    6. public I() {
    7. cells[0] = new Cell(0,4, Tetris.I);
    8. cells[1] = new Cell(0,3, Tetris.I);
    9. cells[2] = new Cell(0,5, Tetris.I);
    10. cells[3] = new Cell(0,6, Tetris.I);
    11. //共有两种旋转状态
    12. states =new State[2];
    13. //初始化两种状态的相对坐标
    14. states[0]=new State(0,0,0,-1,0,1,0,2);
    15. states[1]=new State(0,0,-1,0,1,0,2,0);
    16. }
    17. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class J extends Tetromino {
    6. public J() {
    7. cells[0] = new Cell(0,4, Tetris.J);
    8. cells[1] = new Cell(0,3, Tetris.J);
    9. cells[2] = new Cell(0,5, Tetris.J);
    10. cells[3] = new Cell(1,5, Tetris.J);
    11. states=new State[4];
    12. states[0]=new State(0,0,0,-1,0,1,1,1);
    13. states[1]=new State(0,0,-1,0,1,0,1,-1);
    14. states[2]=new State(0,0,0,1,0,-1,-1,-1);
    15. states[3]=new State(0,0,1,0,-1,0,-1,1);
    16. }
    17. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class L extends Tetromino {
    6. public L() {
    7. cells[0] = new Cell(0,4, Tetris.L);
    8. cells[1] = new Cell(0,3, Tetris.L);
    9. cells[2] = new Cell(0,5, Tetris.L);
    10. cells[3] = new Cell(1,3, Tetris.L);
    11. states=new State[4];
    12. states[0]=new State(0,0,0,-1,0,1,1,-1);
    13. states[1]=new State(0,0,-1,0,1,0,-1,-1);
    14. states[2]=new State(0,0,0,1,0,-1,-1,1);
    15. states[3]=new State(0,0,1,0,-1,0,1,1);
    16. }
    17. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class O extends Tetromino {
    6. public O() {
    7. cells[0] = new Cell(0, 4, Tetris.O);
    8. cells[1] = new Cell(0, 5, Tetris.O);
    9. cells[2] = new Cell(1, 4, Tetris.O);
    10. cells[3] = new Cell(1, 5, Tetris.O);
    11. //无旋转状态
    12. states = new State[0];
    13. }
    14. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class S extends Tetromino {
    6. public S() {
    7. cells[0] = new Cell(0,4, Tetris.S);
    8. cells[1] = new Cell(0,5, Tetris.S);
    9. cells[2] = new Cell(1,3, Tetris.S);
    10. cells[3] = new Cell(1,4, Tetris.S);
    11. //共有两种旋转状态
    12. states =new State[2];
    13. //初始化两种状态的相对坐标
    14. states[0]=new State(0,0,0,1,1,-1,1,0);
    15. states[1]=new State(0,0,1,0,-1,-1,0,-1);
    16. }
    17. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class T extends Tetromino {
    6. public T() {
    7. cells[0] = new Cell(0,4, Tetris.T);
    8. cells[1] = new Cell(0,3, Tetris.T);
    9. cells[2] = new Cell(0,5, Tetris.T);
    10. cells[3] = new Cell(1,4, Tetris.T);
    11. states=new State[4];
    12. states[0]=new State(0,0,0,-1,0,1,1,0);
    13. states[1]=new State(0,0,-1,0,1,0,0,-1);
    14. states[2]=new State(0,0,0,1,0,-1,-1,0);
    15. states[3]=new State(0,0,1,0,-1,0,0,1);
    16. }
    17. }
    1. package xingzhuang;
    2. import sifang.Tetris;
    3. import eluosifangkuai.Cell;
    4. import eluosifangkuai.Tetromino;
    5. public class Z extends Tetromino {
    6. public Z() {
    7. cells[0] = new Cell(1,4, Tetris.Z);
    8. cells[1] = new Cell(0,3, Tetris.Z);
    9. cells[2] = new Cell(0,4, Tetris.Z);
    10. cells[3] = new Cell(1,5, Tetris.Z);
    11. //共有两种旋转状态
    12. states =new State[2];
    13. //初始化两种状态的相对坐标
    14. states[0]=new State(0,0,-1,-1,-1,0,0,1);
    15. states[1]=new State(0,0,-1,1,0,1,1,0);
    16. }
    17. }

    4.游戏运行主类

    1. package sifang;
    2. import eluosifangkuai.Cell;
    3. import eluosifangkuai.Tetromino;
    4. import javax.imageio.ImageIO;
    5. import javax.swing.*;
    6. import java.awt.*;
    7. import java.awt.event.KeyAdapter;
    8. import java.awt.event.KeyEvent;
    9. import java.awt.event.KeyListener;
    10. import java.awt.image.BufferedImage;
    11. import java.io.File;
    12. import java.io.IOException;
    13. import java.security.cert.Certificate;
    14. public class Tetris extends JPanel {
    15. //正在下落的方块
    16. private Tetromino currentOne = Tetromino.randomOne();
    17. //将要下落的方块
    18. private Tetromino nextOne = Tetromino.randomOne();
    19. //游戏主区域
    20. private Cell[][] wall = new Cell[18][9];
    21. //声明单元格的值
    22. private static final int CELL_SIZE = 48;
    23. //游戏分数池
    24. int[] scores_pool = {0, 1, 2, 5, 10};
    25. //当前游戏的分数
    26. private int totalScore = 0;
    27. //当前消除的行数
    28. private int totalLine = 0;
    29. //游戏三种状态 游戏中、暂停、结束
    30. public static final int PLING = 0;
    31. public static final int STOP = 1;
    32. public static final int OVER = 2;
    33. //当前游戏状态值
    34. private int game_state;
    35. //显示游戏状态
    36. String[] show_state = {"P[pause]", "C[continue]", "S[replay]"};
    37. //载入方块图片
    38. public static BufferedImage I;
    39. public static BufferedImage J;
    40. public static BufferedImage L;
    41. public static BufferedImage O;
    42. public static BufferedImage S;
    43. public static BufferedImage T;
    44. public static BufferedImage Z;
    45. public static BufferedImage background;
    46. static {
    47. try {
    48. I = ImageIO.read(new File("images/I.png"));
    49. J = ImageIO.read(new File("images/J.png"));
    50. L = ImageIO.read(new File("images/L.png"));
    51. O = ImageIO.read(new File("images/O.png"));
    52. S = ImageIO.read(new File("images/S.png"));
    53. T = ImageIO.read(new File("images/T.png"));
    54. Z = ImageIO.read(new File("images/Z.png"));
    55. background = ImageIO.read(new File("images/background.png"));
    56. } catch (IOException e) {
    57. e.printStackTrace();
    58. }
    59. }
    60. @Override
    61. public void paint(Graphics g) {
    62. g.drawImage(background, 0, 0, null);
    63. //平移坐标轴
    64. g.translate(22, 15);
    65. //绘制游戏主区域
    66. paintWall(g);
    67. //绘制正在下落的四方格
    68. paintCurrentOne(g);
    69. //绘制下一个将要下落的四方格
    70. paintNextOne(g);
    71. //绘制游戏得分
    72. paintSource(g);
    73. //绘制当前游戏状态
    74. paintState(g);
    75. }
    76. public void start() {
    77. game_state = PLING;
    78. KeyListener l = new KeyAdapter() {
    79. @Override
    80. public void keyPressed(KeyEvent e) {
    81. int code = e.getKeyCode();
    82. switch (code) {
    83. case KeyEvent.VK_DOWN:
    84. sortDropActive();
    85. break;
    86. case KeyEvent.VK_LEFT:
    87. moveleftActive();
    88. break;
    89. case KeyEvent.VK_RIGHT:
    90. moveRightActive();
    91. break;
    92. case KeyEvent.VK_UP:
    93. rotateRightActive();
    94. break;
    95. case KeyEvent.VK_SPACE:
    96. hadnDropActive();
    97. break;
    98. case KeyEvent.VK_P:
    99. //判断当前游戏状态
    100. if (game_state == PLING) {
    101. game_state = STOP;
    102. }
    103. break;
    104. case KeyEvent.VK_C:
    105. if (game_state == STOP) {
    106. game_state = PLING;
    107. }
    108. break;
    109. case KeyEvent.VK_S:
    110. //重新开始
    111. game_state = PLING;
    112. wall = new Cell[18][9];
    113. currentOne = Tetromino.randomOne();
    114. nextOne = Tetromino.randomOne();
    115. totalScore = 0;
    116. totalLine = 0;
    117. break;
    118. }
    119. }
    120. };
    121. //将窗口设置为焦点
    122. this.addKeyListener(l);
    123. this.requestFocus();
    124. while (true) {
    125. if (game_state == PLING) {
    126. try {
    127. Thread.sleep(500);
    128. } catch (InterruptedException e) {
    129. e.printStackTrace();
    130. }
    131. if (camDrop()) {
    132. currentOne.moveDrop();
    133. } else {
    134. landToWall();
    135. destroyLine();
    136. if (isGameOver()) {
    137. game_state = OVER;
    138. } else {
    139. //游戏没有结束
    140. currentOne = nextOne;
    141. nextOne = Tetromino.randomOne();
    142. }
    143. }
    144. }
    145. repaint();
    146. }
    147. }
    148. //创建顺时针旋转
    149. public void rotateRightActive() {
    150. currentOne.rotateRight();
    151. if (outOFBounds() || coincide()) {
    152. currentOne.rotateLeft();
    153. }
    154. }
    155. //瞬间下落
    156. public void hadnDropActive() {
    157. while (true) {
    158. //判断能否下落
    159. if (camDrop()) {
    160. currentOne.moveDrop();
    161. } else {
    162. break;
    163. }
    164. }
    165. //嵌入到墙中
    166. landToWall();
    167. destroyLine();
    168. if (isGameOver()) {
    169. game_state = OVER;
    170. } else {
    171. //游戏没有结束
    172. currentOne = nextOne;
    173. nextOne = Tetromino.randomOne();
    174. }
    175. }
    176. //按键一次,下落一格
    177. public void sortDropActive() {
    178. if (camDrop()) {
    179. //当前四方格下落一格
    180. currentOne.moveDrop();
    181. } else {
    182. landToWall();
    183. destroyLine();
    184. if (isGameOver()) {
    185. game_state = OVER;
    186. } else {
    187. //游戏没有结束
    188. currentOne = nextOne;
    189. nextOne = Tetromino.randomOne();
    190. }
    191. }
    192. }
    193. //单元格嵌入墙中
    194. private void landToWall() {
    195. Cell[] cells = currentOne.cells;
    196. for (Cell cell : cells) {
    197. int row = cell.getRow();
    198. int col = cell.getCol();
    199. wall[row][col] = cell;
    200. }
    201. }
    202. //判断四方格能否下落
    203. public boolean camDrop() {
    204. Cell[] cells = currentOne.cells;
    205. for (Cell cell : cells) {
    206. int row = cell.getRow();
    207. int col = cell.getCol();
    208. //判断是否到达底部
    209. if (row == wall.length - 1) {
    210. return false;
    211. } else if (wall[row + 1][col] != null) {
    212. return false;
    213. }
    214. }
    215. return true;
    216. }
    217. //消除行
    218. public void destroyLine() {
    219. int line = 0;
    220. Cell[] cells = currentOne.cells;
    221. for (Cell cell : cells) {
    222. int row = cell.getRow();
    223. if (isFullLine(row)) {
    224. line++;
    225. for (int i = row; i > 0; i--) {
    226. System.arraycopy(wall[i - 1], 0, wall[i], 0, wall[0].length);
    227. }
    228. wall[0] = new Cell[9];
    229. }
    230. }
    231. //分数池获取分数,累加到总分
    232. totalScore += scores_pool[line];
    233. //总行数
    234. totalLine += line;
    235. }
    236. //判断当前行是否已经满了
    237. public boolean isFullLine(int row) {
    238. Cell[] cells = wall[row];
    239. for (Cell cell : cells) {
    240. if (cell == null) {
    241. return false;
    242. }
    243. }
    244. return true;
    245. }
    246. //判断游戏是否结束
    247. public boolean isGameOver() {
    248. Cell[] cells = nextOne.cells;
    249. for (Cell cell : cells) {
    250. int row = cell.getRow();
    251. int col = cell.getCol();
    252. if (wall[row][col] != null) {
    253. return true;
    254. }
    255. }
    256. return false;
    257. }
    258. private void paintState(Graphics g) {
    259. if (game_state == PLING) {
    260. g.drawString(show_state[PLING], 500, 660);
    261. } else if (game_state == STOP) {
    262. g.drawString(show_state[STOP], 500, 660);
    263. } else {
    264. g.drawString(show_state[OVER], 500, 660);
    265. g.setColor(Color.RED);
    266. g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
    267. g.drawString("GAME OVER!", 30, 400);
    268. }
    269. }
    270. private void paintSource(Graphics g) {
    271. g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
    272. g.drawString("分数: " + totalScore, 500, 250);
    273. g.drawString("行数: " + totalLine, 500, 430);
    274. }
    275. private void paintNextOne(Graphics g) {
    276. Cell[] cells = nextOne.cells;
    277. for (Cell cell : cells) {
    278. int x = cell.getCol() * CELL_SIZE + 370;
    279. int y = cell.getRow() * CELL_SIZE + 25;
    280. g.drawImage(cell.getImage(), x, y, null);
    281. }
    282. }
    283. private void paintCurrentOne(Graphics g) {
    284. Cell[] cells = currentOne.cells;
    285. for (Cell cell : cells) {
    286. int x = cell.getCol() * CELL_SIZE;
    287. int y = cell.getRow() * CELL_SIZE;
    288. g.drawImage(cell.getImage(), x, y, null);
    289. }
    290. }
    291. private void paintWall(Graphics g) {
    292. for (int i = 0; i < wall.length; i++) {
    293. for (int j = 0; j < wall[i].length; j++) {
    294. int x = j * CELL_SIZE;
    295. int y = i * CELL_SIZE;
    296. Cell cell = wall[i][j];
    297. //判断是否有小方块
    298. if (cell == null) {
    299. g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
    300. } else {
    301. g.drawImage(cell.getImage(), x, y, null);
    302. }
    303. }
    304. }
    305. }
    306. //判断是否出界
    307. public boolean outOFBounds() {
    308. Cell[] cells = currentOne.cells;
    309. for (Cell cell : cells) {
    310. int col = cell.getCol();
    311. int row = cell.getRow();
    312. if (row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length-1) {
    313. return true;
    314. }
    315. }
    316. return false;
    317. }
    318. //按键一次,左移一次
    319. public void moveleftActive() {
    320. currentOne.moveLeft();
    321. //判断是否越界或重合
    322. if (outOFBounds() || coincide()) {
    323. currentOne.moveRight();
    324. }
    325. }
    326. //按键一次,右移一次
    327. public void moveRightActive() {
    328. currentOne.moveRight();
    329. //判断是否越界或重合
    330. if (outOFBounds() || coincide()) {
    331. currentOne.moveLeft();
    332. }
    333. }
    334. //判断是否重合
    335. public boolean coincide() {
    336. Cell[] cells = currentOne.cells;
    337. for (Cell cell : cells) {
    338. int row = cell.getRow();
    339. int col = cell.getCol();
    340. if (wall[row][col] != null) {
    341. return true;
    342. }
    343. }
    344. return false;
    345. }
    346. public static void main(String[] args) {
    347. JFrame jFrame = new JFrame("俄罗斯方块");
    348. //创建游戏界面
    349. Tetris panel = new Tetris();
    350. jFrame.add(panel);
    351. //设置可见
    352. jFrame.setVisible(true);
    353. //设置窗口大小
    354. jFrame.setSize(810, 940);
    355. //设置剧中
    356. jFrame.setLocationRelativeTo(null);
    357. //设置窗口关闭时停止
    358. jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    359. //游戏主要开始逻辑
    360. panel.start();
    361. }
    362. }

    运行结果

  • 相关阅读:
    LeetCode:1480.一维数组的动态和
    python基于PHP+MySQL的投资理财网站的设计与实现
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    fastjson2 介绍及使用
    MCE丨重组蛋白常见的融合标签
    【DevOps】Gitlab的安装与升级
    Alad de Qnget
    为什么有的人说技术不重要,有的人说重要?
    记笔记非常好用的一款工具 eDiary
    MyBatis-PLUS使用教程
  • 原文地址:https://blog.csdn.net/m0_73576495/article/details/134522125