Java小程序------俄罗斯方块(Tetris)

俄罗斯方块

相信大家从小就玩过俄罗斯方块的,多余的话就不多说了,代码是有生命的,就让代码来说话好了

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);
			}
		}

	}
}

你可能感兴趣的:(java,界面,俄罗斯方块)