俄罗斯方块
相信大家从小就玩过俄罗斯方块的,多余的话就不多说了,代码是有生命的,就让代码来说话好了
package cn.hncu.games; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.Timer; public class Tetris extends JFrame { private TetrisPanel a; private JMenuItem j1,j2,j3; public Tetris() { // 添加菜单,此处仅示意技术,不写完善 JMenuBar menubar = new JMenuBar(); setJMenuBar(menubar); // 菜单 JMenu menuGame = new JMenu("游戏"); menubar.add(menuGame); // 菜单项 j1 = new JMenuItem("新游戏"); j1.setActionCommand("newGame"); menuGame.add(j1); j2 = new JMenuItem("暂停"); j2.setActionCommand("pause"); menuGame.add(j2); j3 = new JMenuItem("继续"); j3.setActionCommand("resume"); menuGame.add(j3); // 菜单项监听 MenuListener ml = new MenuListener(); j1.addActionListener(ml); j2.addActionListener(ml); j3.addActionListener(ml); //另一种添加方式 menuGame.add("其它").addActionListener(ml); // 为了在菜单监听器类中访问a对象,提升作用域 // TetrisPanel a = new TetrisPanel(); a = new TetrisPanel(); this.addKeyListener(a.listener); // this.add(a);正式开发不用this,运行效率更高 add(a); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(220, 275); setLocation(400, 100); setTitle("俄罗斯方块精简版"); setResizable(false); } public static void main(String[] args) { Tetris te = new Tetris(); te.setVisible(true); } /* * 用面板当画布,界面刷新效果更好 */ class TetrisPanel extends JPanel { private int blockType; // 0-6 3 private int turnState; // 0-3 2 private int x; private int y; private int score; private int delay; private TimerListener listener = new TimerListener(); private Timer timer; // 定义地图,用来存放整个游戏方块区的状态(显示方格或不显示) // 存放块的位置:x=0~11 y=0~21 // ----22行12列(其中一行两列是外框),行列的序号位置跟我们平时写的是相反的map[列号][行号] int[][] map = new int[13][23];// 为解决越界,在边上预留了1列 // 方块的形状: // 第一维代表方块类型(包括7种:S、Z、L、J、I、O、T) // 第二维代表旋转次数 // 第三四维代表方块矩阵 int shapes[][][] = new int[][][] { /* * 模板 { {0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0}, {0,0,0,0,0,0,0,0, 0,0,0,0, * 0,0,0,0}, {0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0}, {0,0,0,0,0,0,0,0, * 0,0,0,0, 0,0,0,0} } */ // I (※把版本1中的横条从第1行换到第2行) { { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } }, // S { { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } }, // Z { { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } }, // J { { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // O { { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // L { { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, // T { { 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } }; public TetrisPanel() { nextBlock(); newGame(); } // 生成一个新的方块 public void nextBlock() { // blockType和turnState两个变量即决定是什么样的方块 // 每次新生成一个块就是产生为这两个变量产生一个新值 blockType = (int) (Math.random() * 1000) % 7; turnState = (int) (Math.random() * 1000) % 4; x = 4; y = 0; if (crash(x, y, blockType, turnState) == 0) { timer.stop(); int option = JOptionPane.showConfirmDialog(this, "Game Over!!,还敢来吗..."); if (option == JOptionPane.OK_OPTION) { newGame(); } else if (option == JOptionPane.NO_OPTION) { System.exit(0); } } } // 初始化地图(外框) public void newGame() { for (int i = 0; i < 12; i++) {// 5 for (int j = 0; j < 22; j++) { map[i][j] = 0; map[11][j] = map[0][j] = 3; } map[i][21] = 3; } // timer = new Timer(300, listener); delay=1000; timer = new Timer(delay, listener); timer.start(); score = 0;// 分数初始化为0 nextBlock(); j3.setEnabled(false);//把“新游戏”菜单灭掉 repaint(); } private void pause() { timer.stop(); } private void resume() { timer.restart(); } // 下落方法 private void down() { if (crash(x, y + 1, blockType, turnState) == 0) { add(x, y, blockType, turnState); nextBlock(); } y++; repaint(); } // 判断是否碰撞 private int crash(int x, int y, int blockType, int turnState) { for (int a = 0; a < 4; a++) { for (int b = 0; b < 4; b++) { if ((shapes[blockType][turnState][a * 4 + b] & map[x + b + 1][y + a]) == 1) { return 0; } } } return 1; } private void add(int x, int y, int blockType, int turnState) { for (int a = 0; a < 4; a++) { for (int b = 0; b < 4; b++) { if (shapes[blockType][turnState][a * 4 + b] == 1) map[x + b + 1][y + a] = shapes[blockType][turnState][a * 4 + b]; } } tryDeline(); } private void turn() { turnState = (turnState + crash(x, y, blockType, (turnState + 1) % 4)) % 4; repaint(); } private void left() { if (x >= 0) { x -= crash(x - 1, y, blockType, turnState); repaint(); } } private void right() { if (x < 8) { x += crash(x + 1, y, blockType, turnState); repaint(); } } public void tryDeline() { for (int b = 0; b < 21; b++) {// b是行号 int c = 1; for (int a = 0; a < 12; a++) {// 10列是真正的方块区,外面有两列是边界 c &= map[a][b]; } // 实心块是1,边界是3。这两者的最后一位都是1,和1&运算的结果是1 if (c == 1) {// 整行的格子要么是实心块,要么是边界。因为只要有一个0,&运算的结果就是0 // 消行 // 从上往下,逐行扫描,把下一行的格子依次往上移 for (int d = b; d > 0; d--) { for (int e = 1; e < 11; e++) { map[e][d] = map[e][d - 1]; } } // 游戏加分 score += 10; delay /= 2; timer.setDelay(delay); } } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g);// 清除残影 // 画当前块 g.setColor(Color.blue); for (int j = 0; j < 16; j++) { if (shapes[blockType][turnState][j] == 1) { g.fillRect((j % 4 + x + 1) * 10, (j / 4 + y) * 10, 10, 10); } } g.setColor(Color.red); // 画地图(已经固定的方块) for (int j = 0; j < 22; j++) { for (int i = 0; i < 12; i++) { if (map[i][j] == 1) { g.fillRect(i * 10, j * 10, 10, 10); // 让堆积块有分界线 g.setColor(Color.green); g.drawRect(i * 10, j * 10, 10, 10); g.setColor(Color.red); } else if (map[i][j] == 3) { g.drawRect(i * 10, j * 10, 10, 10); } } } // 画方块区右侧部分 g.setColor(Color.blue); g.setFont(new Font("aa", Font.BOLD, 18)); g.drawString("score=" + score, 130, 20); g.setFont(new Font("aa", Font.PLAIN, 13)); g.drawString("拒绝盗版游戏", 130, 70); g.drawString("注意自我保护", 130, 90); g.drawString("谨防受骗上当。", 125, 110); g.drawString("适度游戏益脑,", 125, 130); g.drawString("沉迷游戏伤身。", 125, 150); g.drawString("合理安排时间,", 125, 170); g.drawString("享受健康生活。", 125, 190); } class TimerListener extends KeyAdapter implements ActionListener { @Override public void actionPerformed(ActionEvent e) { down(); } @Override public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); switch (keyCode) { case KeyEvent.VK_DOWN: down(); break; case KeyEvent.VK_UP: turn(); break; case KeyEvent.VK_LEFT: left(); break; case KeyEvent.VK_RIGHT: right(); } } } } class MenuListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("newGame")) { a.newGame(); } else if (e.getActionCommand().equals("pause")) { a.pause(); j2.setEnabled(false); j3.setEnabled(true); } else if (e.getActionCommand().equals("resume")) { a.resume(); j3.setEnabled(false); j2.setEnabled(true); } } } }