• 俄罗斯方块


    一.准备工作

    先创建一个新的Java项目命名为“俄罗斯方块”。再在该项目中创建一个文件夹命名为”images”,并将所需的图片素材拖入该文件夹。

    二.代码呈现 

    编写小方块类:

    1. import java.awt.image.BufferedImage;
    2. /**
    3. * 描述:小方块类
    4. * 属性:行,列以及单元格的图片
    5. * 方法: 左移一格,右移一格,下移一格
    6. */
    7. public class Cell {
    8. private int row;
    9. private int col;
    10. private BufferedImage image;
    11. public Cell() {
    12. }
    13. public Cell(int row, int col, BufferedImage image) {
    14. this.row = row;
    15. this.col = col;
    16. this.image = image;
    17. }
    18. public int getRow() {
    19. return row;
    20. }
    21. public void setRow(int row) {
    22. this.row = row;
    23. }
    24. public int getCol() {
    25. return col;
    26. }
    27. public void setCol(int col) {
    28. this.col = col;
    29. }
    30. public BufferedImage getImage() {
    31. return image;
    32. }
    33. public void setImage(BufferedImage image) {
    34. this.image = image;
    35. }
    36. //左移
    37. public void left() {
    38. col--;
    39. }
    40. //右移
    41. public void right() {
    42. col++;
    43. }
    44. //下移
    45. public void soft() {
    46. row++;
    47. }
    48. }

    编写四方格父类:

    1. /**
    2. * 描述:四方格父类
    3. * 属性:Cell[]数组用于创建4个小方块
    4. * 方法:左移一格,右移一格,下移一格,变形
    5. */
    6. public class Tetromino {
    7. protected Cell[] cells = new Cell[4];
    8. //左移
    9. public void moveLeft() {
    10. for (Cell cell : cells) {
    11. cell.left();
    12. }
    13. }
    14. //右移
    15. public void moveRight() {
    16. for (Cell cell : cells) {
    17. cell.right();
    18. }
    19. }
    20. //下移
    21. public void sftDrop() {
    22. for (Cell cell : cells) {
    23. cell.drop();
    24. }
    25. }
    26. //随机生成四方格
    27. public static Tetromino randomOne() {
    28. int num = (int)(Math.random() * 7);
    29. Tetromino tetromino = null;
    30. switch (num) {
    31. case 0 :
    32. tetromino = new I();
    33. break;
    34. case 1 :
    35. tetromino = new J();
    36. break;
    37. case 2 :
    38. tetromino = new L();
    39. break;
    40. case 3 :
    41. tetromino = new O();
    42. break;
    43. case 4 :
    44. tetromino = new S();
    45. break;
    46. case 5 :
    47. tetromino = new T();
    48. break;
    49. case 6 :
    50. tetromino = new Z();
    51. break;
    52. }
    53. return tetromino;
    54. }
    55. //编写旋转状态
    56. protected State[] states;
    57. //声明旋转次数
    58. protected int count = 10000;
    59. /**描述:四方格旋转状态的内部类
    60. * 属性:记录四方格的相对位置
    61. */
    62. class State {
    63. int row0,col0,row1,col1,row2,col2,row3,col3;
    64. public State(){
    65. }
    66. public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) {
    67. this.row0 = row0;
    68. this.col0 = col0;
    69. this.row1 = row1;
    70. this.col1 = col1;
    71. this.row2 = row2;
    72. this.col2 = col2;
    73. this.row3 = row3;
    74. this.col3 = col3;
    75. }
    76. public int getRow0() {
    77. return row0;
    78. }
    79. public void setRow0(int row0) {
    80. this.row0 = row0;
    81. }
    82. public int getRow1() {
    83. return row1;
    84. }
    85. public void setRow1(int row1) {
    86. this.row1 = row1;
    87. }
    88. public int getRow2() {
    89. return row2;
    90. }
    91. public void setRow2(int row2) {
    92. this.row2 = row2;
    93. }
    94. public int getRow3() {
    95. return row3;
    96. }
    97. public void setRow3(int row3) {
    98. this.row3 = row3;
    99. }
    100. public int getCol0() {
    101. return col0;
    102. }
    103. public void setCol0(int col0) {
    104. this.col0 = col0;
    105. }
    106. public int getCol1() {
    107. return col1;
    108. }
    109. public void setCol1(int col1) {
    110. this.col1 = col1;
    111. }
    112. public int getCol2() {
    113. return col2;
    114. }
    115. public void setCol2(int col2) {
    116. this.col2 = col2;
    117. }
    118. public int getCol3() {
    119. return col3;
    120. }
    121. public void setCol3(int col3) {
    122. this.col3 = col3;
    123. }
    124. }
    125. //编写顺时针旋转四方格方法
    126. public void rotateRight() {
    127. if (states.length == 0) {
    128. return;
    129. }
    130. //旋转次数加1
    131. count++;
    132. //获取当前状态
    133. State s = states[count % states.length];
    134. Cell cell = cells[0];
    135. int row = cell.getRow();
    136. int col = cell.getCol();
    137. //变形
    138. cells[1].setRow(row + s.row1);
    139. cells[1].setCol(col + s.col1);
    140. cells[2].setRow(row + s.row2);
    141. cells[2].setCol(col + s.col2);
    142. cells[3].setRow(row + s.row3);
    143. cells[3].setCol(col + s.col3);
    144. }
    145. //逆时针旋转四方格方法
    146. public void rotateLeft() {
    147. //旋转次数加1
    148. count--;
    149. //获取当前状态
    150. State s = states[count % states.length];
    151. Cell cell = cells[0];
    152. int row = cell.getRow();
    153. int col = cell.getCol();
    154. //变形
    155. cells[1].setRow(row + s.row1);
    156. cells[1].setCol(col + s.col1);
    157. cells[2].setRow(row + s.row2);
    158. cells[2].setCol(col + s.col2);
    159. cells[3].setRow(row + s.row3);
    160. cells[3].setCol(col + s.col3);
    161. }
    162. //顺时针旋转
    163. public void rotateRightAction() {
    164. Tetromino currentOne = null;
    165. currentOne.rotateRight();
    166. //判断是否越界或者重合,否则恢复原来的状态
    167. if (outOfBounds() || coincide()) {
    168. currentOne.rotateLeft();
    169. }
    170. }
    171. private boolean coincide() {
    172. // TODO Auto-generated method stub
    173. return false;
    174. }
    175. private boolean outOfBounds() {
    176. // TODO Auto-generated method stub
    177. return false;
    178. }
    179. //判断游戏是否结束,结束返回true,继续返回false
    180. public boolean isGameOver() {
    181. Cell[] cells = nextOne.cells;
    182. for (Cell cell : cells) {
    183. int row = cell.getRow();
    184. int col = cell.getCol();
    185. if (wall[row][col] != null) {
    186. return true;
    187. }
    188. }
    189. return false;
    190. }
    191. //判断当前行是否满,满返回true,没有满返回false
    192. public boolean isFullLine(int row) {
    193. Cell[] cells = wall[row];
    194. for (Cell cell : cells) {
    195. if (cell == null) {
    196. return false;
    197. }
    198. }
    199. return true;
    200. }
    201. //创建销行方法
    202. public void destroyLine() {
    203. //统计当前形参行数
    204. int line = 0;
    205. Cell[] cells = currentOne.cells;
    206. for (Cell cell : cells) {
    207. int row = cell.getRow();
    208. //判断当前行是否满
    209. if (isFullLine(row)) {
    210. line++;
    211. //将消除行以上的方块下落到对应行数
    212. for (int i = row; i > 0; i--) {
    213. System.arraycopy(wall[i - 1],0,wall[i],0,wall[0].length);
    214. }
    215. //重新创造第一行
    216. wall[0] = new Cell[9];
    217. }
    218. }
    219. //更新分数
    220. totalScore += scores_pool[line];
    221. //更新消除行数
    222. totalLine += line;
    223. }
    224. //判断四方格能否下落
    225. public boolean canDrop() {
    226. Cell[] cells = currentOne.cells;
    227. for (Cell cell : cells) {
    228. int row = cell.getRow();
    229. int col = cell.getCol();
    230. //判断能否全部到达底部
    231. if (row == wall.length - 1) {
    232. return false;
    233. } else if(wall[row + 1][col] != null) { //判断该位置是否有方块
    234. return false;
    235. }
    236. }
    237. return true;
    238. }
    239. //按键一次四方格下落一个
    240. public void sortDropAction() {
    241. //判断能否下落
    242. if (canDrop()) {
    243. //当前四方格下落一格
    244. currentOne.softDrop();
    245. } else {
    246. //把四方格嵌入墙中
    247. landToWall();
    248. //判断能否销行
    249. destroyLine();
    250. //判断游戏是否结束
    251. if (isGameOver()) {
    252. game_state = GAMEOVER;
    253. } else {
    254. //继续生成四方格
    255. currentOne = nextOne;
    256. nextOne = Tetromino.randomOne();
    257. }
    258. }
    259. }
    260. //把四方格嵌入墙中
    261. private void landToWall() {
    262. Cell[] cells = currentOne.cells;
    263. for (Cell cell : cells) {
    264. int row = cell.getRow();
    265. int col = cell.getCol();
    266. wall[row][col] = cell;
    267. }
    268. }
    269. //瞬间下落
    270. public void handDropAction() {
    271. while (canDrop()) {
    272. currentOne.softDrop();
    273. }
    274. //把四方格嵌入墙中
    275. landToWall();
    276. //判断能否销行
    277. destroyLine();
    278. //判断游戏是否结束
    279. if (isGameOver()) {
    280. game_state = GAMEOVER;
    281. } else {
    282. //继续生成四方格
    283. currentOne = nextOne;
    284. nextOne = Tetromino.randomOne();
    285. }
    286. }
    287. public void start() {
    288. game_state = PLAYING;
    289. KeyListener listener = new KeyAdapter() {
    290. @Override
    291. public void keyPressed(KeyEvent e) {
    292. int code = e.getKeyCode();
    293. switch (code) {
    294. case KeyEvent.VK_DOWN: //↓
    295. sortDropAction(); //下落一格
    296. break;
    297. case KeyEvent.VK_LEFT://←
    298. moveLeftAction(); //左移一格
    299. break;
    300. case KeyEvent.VK_RIGHT: //→
    301. moveRightAction(); //右移一格
    302. break;
    303. case KeyEvent.VK_UP://↑
    304. rotateRightAction();//顺时针旋转
    305. break;
    306. case KeyEvent.VK_SPACE://空格
    307. handDropAction();//瞬间下落
    308. break;
    309. case KeyEvent.VK_P: //p
    310. //判断游戏是否在运行,没有才能暂停
    311. if (game_state == PLAYING) {
    312. game_state = PAUSE;
    313. }
    314. break;
    315. case KeyEvent.VK_C:
    316. //游戏暂停后,才能继续
    317. if (game_state == PAUSE) {
    318. game_state = PLAYING;
    319. }
    320. break;
    321. case KeyEvent.VK_R:
    322. //重新开始游戏,把游戏状态变为正在游戏
    323. game_state = PLAYING;
    324. //界面清空
    325. wall = new Cell[ROW][COL];
    326. currentOne = Tetromino.randomOne();
    327. nextOne = Tetromino.randomOne();
    328. //数据清空
    329. totalLine = 0;
    330. totalScore = 0;
    331. break;
    332. }
    333. }
    334. };
    335. //把俄罗斯方块窗口设置为焦点
    336. this.addKeyListener(listener);
    337. this.requestFocus();
    338. while(true){
    339. //判断,当前游戏状态在游戏中时,每隔0.5秒下落
    340. if(game_state == PLAYING){
    341. try {
    342. Thread.sleep(700);
    343. } catch (InterruptedException e) {
    344. e.printStackTrace();
    345. }
    346. //判断能否下落
    347. if(canDrop()){
    348. currentOne.softDrop();
    349. }else{
    350. //嵌入到墙中
    351. landToWall();
    352. //判断能否消行
    353. destroyLine();
    354. //判断游戏是否结束
    355. if(isGameOver()){
    356. game_state = GAMEOVER;
    357. }else{
    358. currentOne = nextOne;
    359. nextOne = Tetromino.randomOne();
    360. }
    361. }
    362. }
    363. //重新绘制
    364. repaint();
    365. }
    366. }
    367. }

    编写俄罗斯方块主类:

    1. import javax.imageio.ImageIO;
    2. import javax.swing.*;
    3. import java.awt.*;
    4. import java.awt.image.BufferedImage;
    5. import java.io.File;
    6. import java.io.IOException;
    7. //俄罗斯方块主类
    8. public class Tetris extends JPanel {
    9. static int ROW=18;
    10. static int COL=9;
    11. //声明正在下落的方块
    12. private Tetromino currentOne = Tetromino.randomOne();
    13. //声明将要下落的方块
    14. private Tetromino nextOne = Tetromino.randomOne();
    15. //声明游戏主区域
    16. private Cell[][] wall = new Cell[ROW][COL];
    17. //声明单元格像素为48像素
    18. private static final int CELL_SIZE=48;
    19. //游戏分数池
    20. int[] scores_pool = {0, 1, 2, 5, 10};
    21. //游戏总分
    22. private int totalScore = 0;
    23. //游戏消除总行数
    24. private int totalLine = 0;
    25. //游戏的状态:游戏中,游戏暂停,游戏结束
    26. private static final int PLAYING=0;
    27. private static final int PAUSE=1;
    28. private static final int GAMEOVER=2;
    29. //声明变量来存放当前游戏状态
    30. private int game_state;
    31. //数组显示当前游戏状态
    32. String[] show_state= {"P[暂停]","C[继续]","R[重开]"};
    33. //静态载入图片
    34. public static BufferedImage I;
    35. public static BufferedImage J;
    36. public static BufferedImage L;
    37. public static BufferedImage O;
    38. public static BufferedImage S;
    39. public static BufferedImage T;
    40. public static BufferedImage Z;
    41. public static BufferedImage backImage;
    42. static {
    43. try {
    44. I = ImageIO.read(new File(pathname:"images/I.png"));
    45. J = ImageIO.read(new File(pathname:"images/J.png"));
    46. L = ImageIO.read(new File(pathname:"images/L.png"));
    47. O = ImageIO.read(new File(pathname:"images/O.png"));
    48. S = ImageIO.read(new File(pathname:"images/S.png"));
    49. T = ImageIO.read(new File(pathname:"images/T.png"));
    50. Z = ImageIO.read(new File(pathname:"images/Z.png"));
    51. backImage=ImageIO.read(new File(pathname:"images/background.png"));
    52. } catch (IOException e) {
    53. e.printStackTrace();
    54. }
    55. }
    56. public static void main(String[] args) {
    57. //创建窗口对象
    58. JFrame frame = new JFrame(title:"俄罗斯方块");
    59. //创建游戏窗口(即面板)
    60. Tetris panel = new Tetris();
    61. //把面板嵌入到窗口中
    62. frame.add(panel);
    63. //设置可见
    64. frame.setVisible(true);
    65. //设置窗口尺寸
    66. frame.setSize(width:810,height:940);
    67. //设置窗口居中
    68. frame.setLocationRelativeTo(null);
    69. //设置窗口关闭时程序中止
    70. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    71. //游戏逻辑封装在方法中
    72. panel.start();
    73. }
    74. @Override
    75. public void paint(Graphics g) {
    76. g.drawImage(backImage,x:0,y:0,observer:null);
    77. //平移坐标轴
    78. g.translate(x:22, y:15);
    79. //绘制游戏主区域
    80. paintWall(g);
    81. //绘制正在下落的四方格
    82. paintCurrentOne(g);
    83. //绘制下一个下落的四方格
    84. paintNextOne(g);
    85. //绘制游戏得分
    86. paintScore(g);
    87. //绘制游戏当前状态
    88. paintState(g);
    89. }
    90. //绘制游戏当前状态
    91. private void paintState(Graphics g) {
    92. if(game_state==PLAYING) {
    93. g.drawString(show_state[0],x:500,y:660);
    94. }else if(game_state==PAUSE) {
    95. g.drawString(show_state[1],x:500,y:660);
    96. }else if(game_state==GAMEOVER) {
    97. g.drawString(show_state[2],x:500,y:660);
    98. g.setColor(Color.red);
    99. g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,size:60));
    100. g.drawString(str:"GAMEOVER!",x:30,y:400);
    101. }
    102. }
    103. private void paintNextOne(Graphics g) {
    104. Cell[] cells=nextOne.cells;
    105. for(Cell cell:cells) {
    106. int x=cell.getCol()*CELL_SIZE+370;
    107. int y=cell.getRow()*CELL_SIZE+25;
    108. g.drawImage(cell.getImage(),x,y,observer:null);
    109. }
    110. }
    111. private void paintCurrentOne(Graphics g) {
    112. Cell[] cells=currentOne.cells;
    113. for(Cell cell:cells) {
    114. int x=cell.getCol()*CELL_SIZE;
    115. int y=cell.getRow()*CELL_SIZE;
    116. g.drawImage(cell.getImage(),x,y,observer:null);
    117. }
    118. }
    119. private void paintWall(Graphics g) {
    120. for(int i=0;i
    121. for(int j=0;j
    122. int x=j*CELL_SIZE;
    123. int y=i*CELL_SIZE;
    124. Cell cell=wall[i][j];
    125. //判断当前单元格是否有小方格,如果无则绘制矩形,否则将小方块嵌到墙中
    126. if(cell==null) {
    127. g.drawRect(x,y,CELL_SIZE,CELL_SIZE);
    128. }else {
    129. g.drawImage(cell.getImage(), x, y, observer.null);
    130. }
    131. }
    132. }
    133. }
    134. //判断方块是否出界,出界返回true,没有则返回false
    135. public boolean outOfBounds() {
    136. Cell[] cells = currentOne.cells;
    137. for (Cell cell : cells) {
    138. int col = cell.getCol();
    139. int row = cell.getRow();
    140. if (col < 0 || col > COL - 1 || row < 0 || row > ROW - 1) {
    141. return true;
    142. }
    143. }
    144. return false;
    145. }
    146. //判断方块是否重合,重合返回true,没有返回false
    147. public boolean coincide() {
    148. Cell[] cells = currentOne.cells;
    149. for (Cell cell : cells) {
    150. int col = cell.getCol();
    151. int row = cell.getRow();
    152. if (wall[row][col] != null) {
    153. return true;
    154. }
    155. }
    156. return false;
    157. }
    158. //按键←触发左移
    159. public void moveLeftAction() {
    160. currentOne.moveLeft();
    161. //判断是否越界或者重合,如果是则右移恢复原来的状态,不是则左移
    162. if (outOfBounds() || coincide()) {
    163. currentOne.moveRight();
    164. }
    165. }
    166. //按键→触发右移
    167. public void moveRightAction() {
    168. currentOne.moveRight();
    169. //判断是否越界或者重合,如果是则左移恢复原来的状态,不是则右移
    170. if (outOfBounds() || coincide()) {
    171. currentOne.moveLeft();
    172. }
    173. }
    174. }

    分别创建并初始化7种形状:

    1. public class I extends Tetromino{
    2. public I() {
    3. cells[0] = new Cell(0,4,Tetris.I);
    4. cells[1] = new Cell(0,3,Tetris.I);
    5. cells[2] = new Cell(0,5,Tetris.I);
    6. cells[3] = new Cell(0,6,Tetris.I);
    7. //两种状态
    8. states = new State[2];
    9. //相对坐标
    10. states[0] = new State(0,0,0,-1,0,1,0,2);
    11. states[1] = new State(0,0,-1,0,1,0,2,0);
    12. }
    13. }
    1. public class J extends Tetromino{
    2. public J() {
    3. cells[0] = new Cell(0,4,Tetris.J);
    4. cells[1] = new Cell(0,3,Tetris.J);
    5. cells[2] = new Cell(0,5,Tetris.J);
    6. cells[3] = new Cell(1,5,Tetris.J);
    7. //4种状态
    8. states = new State[4];
    9. states[0] = new State(0,0,0,1,0,1,1,1);
    10. states[1] = new State(0,0,-1,0,1,0,1,-1);
    11. states[2] = new State(0,0,0,1,0,-1,-1,-1);
    12. states[3] = new State(0,0,1,0,-1,0,-1,1);
    13. }
    14. }
    1. public class L extends Tetromino{
    2. public L() {
    3. cells[0] = new Cell(0,4,Tetris.L);
    4. cells[1] = new Cell(0,3,Tetris.L);
    5. cells[2] = new Cell(0,5,Tetris.L);
    6. cells[3] = new Cell(1,3,Tetris.L);
    7. //4种状态
    8. states = new State[4];
    9. //初始化
    10. states[0] = new State(0,0,0,-1,0,1,1,-1);
    11. states[1] = new State(0,0,-1,0,1,0,-1,-1);
    12. states[2] = new State(0,0,0,1,0,-1,-1,1);
    13. states[3] = new State(0,0,1,0,-1,0,1,1);
    14. }
    15. }
    1. public class O extends Tetromino{
    2. public O() {
    3. cells[0] = new Cell(0,4,Tetris.O);
    4. cells[1] = new Cell(0,5,Tetris.O);
    5. cells[2] = new Cell(1,4,Tetris.O);
    6. cells[3] = new Cell(1,5,Tetris.O);
    7. //0种状态
    8. states = new State[0];
    9. }
    10. }
    1. public class S extends Tetromino{
    2. public S() {
    3. cells[0] = new Cell(0,4,Tetris.S);
    4. cells[1] = new Cell(0,5,Tetris.S);
    5. cells[2] = new Cell(1,3,Tetris.S);
    6. cells[3] = new Cell(1,4,Tetris.S);
    7. //2种状态
    8. states = new State[2];
    9. //初始化相对位置
    10. states[0] = new State(0,0,0,1,1,-1,1,0);
    11. states[1] = new State(0,0,1,0,-1,-1,0,-1);
    12. }
    13. }
    1. public class T extends Tetromino{
    2. public T() {
    3. cells[0] = new Cell(0,4,Tetris.T);
    4. cells[1] = new Cell(0,3,Tetris.T);
    5. cells[2] = new Cell(0,5,Tetris.T);
    6. cells[3] = new Cell(1,4,Tetris.T);
    7. //4种状态
    8. states = new State[4];
    9. //初始化相对坐标
    10. states[0] = new State(0,0,0,-1,0,1,1,0);
    11. states[1] = new State(0,0,-1,0,1,0,0,-1);
    12. states[2] = new State(0,0,0,1,0,-1,-1,0);
    13. states[3] = new State(0,0,1,0,-1,0,0,1);
    14. }
    15. }
    1. public class Z extends Tetromino{
    2. public Z() {
    3. cells[0] = new Cell(1,4,Tetris.Z);
    4. cells[1] = new Cell(0,3,Tetris.Z);
    5. cells[2] = new Cell(0,4,Tetris.Z);
    6. cells[3] = new Cell(1,5,Tetris.Z);
    7. //两种状态
    8. states = new State[2];
    9. //初始化相对位置
    10. states[0] = new State(0,0,-1,-1,-1,0,0,1);
    11. states[1] = new State(0,0,-1,1,0,1,1,0);
    12. }
    13. }

    三.结果呈现

  • 相关阅读:
    【stm32】大一上学期笔记复制
    22年建模经验交流
    spark on hive
    微信小程序如何在切换页面后原页面状态不变
    【踩坑系列】uniapp之h5 跨域的问题
    IIS通过ARR实现负载均衡
    【JavaScript】运算符与表达式、控制语句、常用API
    【Ansible自动化运维工具 1】Ansible常用模块详解(附各模块应用实例和Ansible环境安装部署)
    Mysql应用日志时间与系统时间相差八小时
    【数学】旋转后仍为函数图像问题
  • 原文地址:https://blog.csdn.net/m0_73900459/article/details/134483257