java实现俄罗斯方块游戏

1.功能需求
2.软件功能架构图
3.界面设计
4.程序逻辑图
5.实现代码

  1. 创建控制面板并添加按钮
  2. 初始化界面
  3. 添加事件监听
  4. 创建方块
  5. 实现对方块操作
  6. 游戏主类,实现游戏控制

功能需求

1、 在二维平面里面用各种随机产生的方块堆积木,每满一行消去一行,当达到顶部时,游戏结束。
2、 玩家通过方向键来控制方块转动,左移,右移和直落。
3、 每种类型的方块都有颜色。
4、 玩家能够在玩的过程中给出分数,分数是由方块的类型决定的,每堆积一个方块就把分数累加到总分中。
5、 游戏有暂停,开始,结束,游戏规则和游戏说明等控制

软件功能架构图

在这里插入图片描述

界面设计

游戏主类继承JFrame类,负责游戏的全局控制。内含:
(1)GameCanvas画布类的实例对象(用来存放小方格)
(2)一个保存当前活动块的(RussiaBlock)实例的对象
(3)一个保存当前控制面板(ControlPanel)实例的对象

程序逻辑图

在这里插入图片描述

代码实现

1、创建控制面板并添加按钮

public class ControlPanel extends JPanel {
	private static final long serialVersionUID = 3900659640646175724L;// 用来表明不同版本之间类的兼容性

	// 定义文本框
	private JTextField tfLevel = new JTextField("" + RussiaBlocksGame.DEFAULT_LEVEL), tfScore = new JTextField("0"),
			tfTime = new JTextField(" ");

	// 定义按钮
	private JButton btPlay = new JButton("开始"), btPause = new JButton("暂停"), btStop = new JButton("停止"),
			btTurnLevelUp = new JButton("增加难度"), btTurnLevelDown = new JButton("降低难度");

	// 创建面板容器类为边界布局BorderLayout()
	private JPanel plTip = new JPanel(new BorderLayout());

	private TipPanel plTipBlock = new TipPanel();

	// 创建信息面板容器类为网格布局GridLayout(4,1),4行1列
	private JPanel plInfo = new JPanel(new GridLayout(4, 1));

	// 创建按钮面板容器类为网格布局GridLayout(6,1)
	private JPanel plButton = new JPanel(new GridLayout(6, 1));

	// 定义时间类
	// private Timer timer;

	// 创建组件边框Boreder,EtchedBorder“浮雕化”边框
	private Border border = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140));

	/*
	 * 控制面板类的构造函数
	 */
	public ControlPanel(final RussiaBlocksGame game) {
		// TODO Auto-generated constructor stub

		// 创建网格布局,GridLayout(3,1,0,2), 指定 行数 和 列数 的网格布局, 并指定 水平 和 竖直 网格间隙
		setLayout(new GridLayout(3, 1, 0, 2));

		// 添加组件
		plTip.add(new JLabel("下一个方块"), BorderLayout.NORTH);
		plTip.add(plTipBlock);
		plTip.setBorder(border);

		plInfo.add(new JLabel("难度系数"));
		plInfo.add(tfLevel);
		plInfo.add(new JLabel("得分"));
		plInfo.add(tfScore);
		plInfo.setBorder(border);

		plButton.add(btPlay);
		btPlay.setEnabled(true);
		plButton.add(btPause);
		btPause.setEnabled(false);
		plButton.add(btStop);
		btStop.setEnabled(false);
		plButton.add(btTurnLevelDown);
		plButton.add(btTurnLevelUp);
		plButton.setBorder(border);

		tfLevel.setEnabled(false);
		tfScore.setEnabled(false);
		tfTime.setEnabled(false);

		add(plTip);
		add(plInfo);
		add(plButton);
		}

2、初始化界面

	// 初始化菜单栏
	private JMenuBar bar = new JMenuBar();
	private JMenu mGame = new JMenu(" 游戏"), mControl = new JMenu(" 控制"), mInfo = new JMenu("帮助");
	private JMenuItem miNewGame = new JMenuItem("新游戏"), miSetBlockColor = new JMenuItem("设置方块颜色..."),
			miSetBackColor = new JMenuItem("设置背景颜色..."), miTurnHarder = new JMenuItem("升高游戏难度"),
			miTurnEasier = new JMenuItem("降低游戏难度"), miExit = new JMenuItem("退出"), miPlay = new JMenuItem("开始"),
			miPause = new JMenuItem("暂停"), miResume = new JMenuItem("恢复"), miStop = new JMenuItem("终止游戏"),
			miRule = new JMenuItem("游戏规则"), miAuthor = new JMenuItem("关于本游戏");

	/**
	 * 建立并设置窗口菜单
	 */
	private void creatMenu() {
		bar.add(mGame);
		bar.add(mControl);
		bar.add(mInfo);

		mGame.add(miNewGame);
		mGame.addSeparator();
		mGame.add(miSetBlockColor);
		mGame.add(miSetBackColor);
		mGame.addSeparator();
		mGame.add(miTurnHarder);
		mGame.add(miTurnEasier);
		mGame.addSeparator();
		mGame.add(miExit);
		mControl.add(miPlay);
		miPlay.setEnabled(true);
		mControl.add(miPause);
		miPause.setEnabled(false);
		mControl.add(miResume);
		miResume.setEnabled(false);
		mControl.add(miStop);
		miStop.setEnabled(false);

		mInfo.add(miRule);
		mInfo.add(miAuthor);
		setJMenuBar(bar);

		miNewGame.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				stopGame();
				reset();
				setLevel(DEFAULT_LEVEL);
			}
		});

		// 设置方块颜色
		miSetBlockColor.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Color newFrontColor = JColorChooser.showDialog(RussiaBlocksGame.this, "设置方块颜色",
						canvas.getBackgroundColor());
				if (newFrontColor != null) {
					canvas.setBlockColor(newFrontColor);
				}
			}
		});

		// 设置背景颜色
		miSetBackColor.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Color newBackColor = JColorChooser.showDialog(RussiaBlocksGame.this, "设置背景颜色",
						canvas.getBackgroundColor());
				if (newBackColor != null) {
					canvas.setBackgroundColor(newBackColor);
				}
			}
		});

		// 定义菜单栏"关于"的功能,弹出确认框。
		miAuthor.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(null, "软件工程(4)班\n3115005372\n杨宇杰\n©一切解释权归杨宇杰所有", "关于俄罗斯方块 - 2016", 1);
			}
		});

		// 游戏规则说明
		miRule.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JOptionPane.showMessageDialog(null,
						"由小方块组成的不同形状的板块陆续从屏幕上方落下来,\n玩家通过调整板块的位置和方向,使它们在屏幕底部拼\n出完整的一条或几条。这些完整的横条会随即消失,给新\n落下来的板块腾出空间,与此同时,玩家得到分数奖励。\n没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,\n玩家便告输,游戏结束。",
						"游戏规则", 1);
			}
		});

		// 增加难度
		miTurnHarder.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int curLevel = getLevel();
				if (!playing && curLevel < MAX_LEVEL) {
					setLevel(curLevel + 1);
				}
			}
		});

		// 减少难度
		miTurnEasier.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int curLevel = getLevel();
				if (!playing && curLevel > 1) {
					setLevel(curLevel - 1);
				}
			}
		});

		// 退出按钮动作响应
		miExit.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});

	}

3、添加事件监听

		/*
		 * 添加事件监听
		 */
		/*
		 * 开始游戏
		 */
		btPlay.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				// TODO Auto-generated method stub
				game.playGame();

			}
		});

		/*
		 * 暂停游戏
		 */
		btPause.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				// TODO Auto-generated method stub
				if (btPause.getText().equals("暂停")) {
					game.pauseGame();
				} else {
					game.resumeGame();
				}
			}
		});

		/*
		 * 停止游戏
		 */
		btStop.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				// TODO Auto-generated method stub
				game.stopGame();

			}
		});

		/*
		 * 升高难度
		 */
		btTurnLevelUp.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				// TODO Auto-generated method stub
				try {
					int level = Integer.parseInt(tfLevel.getText());
					if (level < RussiaBlocksGame.MAX_LEVEL) {
						tfLevel.setText("" + (level + 1));

					}
				} catch (NumberFormatException e) {
					// TODO: handle exception
					requestFocus();
				}
			}
		});

		/*
		 * 降低游戏难度
		 */
		btTurnLevelDown.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				// TODO Auto-generated method stub
				try {
					int level = Integer.parseInt(tfLevel.getText());
					if (level > 1) {
						tfLevel.setText("" + (level - 1));

					}

				} catch (NumberFormatException e) {
					// TODO: handle exception
					requestFocus();
				}

			}
		});

		/*
		 * 主要用于解决Jframe窗口大小变化时,里面的组件的位置也会自适应的移动。
		 */
		addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent ce) {
				plTipBlock.fanning();
			}
		});

4、创建方块

public class ErsBox implements Cloneable {

	private boolean isColor;
	private Dimension size = new Dimension(); // Dimension类封装单个对象中组件的宽度和高度(精确到整数)

	/*
	 * 方格类构造函数 isColor是不是用前景色为此方格着色,true前景色,false背景色
	 */
	public ErsBox(boolean isColor) {
		// TODO Auto-generated constructor stub
		this.isColor = isColor;
	}

	/*
	 * 设置方格的颜色 true前景色,false背景色
	 */
	public void setColor(boolean isColor) {
		// TODO Auto-generated method stub
		this.isColor = isColor;

	}

	/*
	 * 得到此方格的尺寸
	 */
	public Dimension getSize() {
		return size;
	}

	/**
	 * 设置方格的尺寸,
	 *
	 * @param size Dimension ,方格的尺寸
	 */
	public void setSize(Dimension size) {
		this.size = size;
	}

	/*
	 * 覆盖object的object clone(),实现克隆
	 */
	public Object clone() {
		Object cloned = null;
		try {
			cloned = super.clone();
		} catch (Exception ex) {
			// TODO: handle exception
			ex.printStackTrace();
		}
		return cloned;

	}

	/**
	 * 此方格是不是用前景色表现
	 *
	 * @return boolean ,true用前景色表现,false 用背景色表现
	 */
	public boolean isColorBox() {
		// TODO Auto-generated method stub
		return isColor;
	}

}

5、实现对方块操作

public class ErsBlock extends Thread {

	// 一个块占得4行
	public static final int BOXES_ROWS = 4;

	// 一个块占4列
	public static final int BOXES_COLS = 4;

	/*
	 * 让升级变化平滑的因子,避免最后几级之间的速度相差近一倍
	 */
	public final static int LEVEL_FLATNESS_GENE = 3;

	// 相近的两级之间,块每下落一行的时间差别为多少(毫秒)
	public final static int BETWEEN_LEVELS_DEGRESS_TIME = 50;

	// 方块的样式数目为7
	public final static int BLOCK_KIND_NUMBER = 7;

	// 每一个样式的方块反转状态种类为4
	public final static int BLOCK_STASTUS_NUMBER = 4;

	/**
	 * 分别对应7中模型的28中状态
	 */
	public final static int[][] STYLES = { // 共28种状态
			{ 0x0f00, 0x4444, 0x0f00, 0x4444 }, // 长条型的四种状态
			{ 0x04e0, 0x0464, 0x00e4, 0x04c4 }, // T型的四种状态
			{ 0x4620, 0x6c00, 0x4620, 0x6c00 }, // 反Z型的四种状态
			{ 0x2640, 0xc600, 0x2640, 0xc600 }, // Z型的四种状态
			{ 0x6220, 0x1700, 0x2230, 0x0740 }, // 7型的四种状态
			{ 0x6440, 0x0e20, 0x44c0, 0x8e00 }, // 反7型的四种状态
			{ 0x0660, 0x0660, 0x0660, 0x0660 }, // 方块的四种状态
	};

	private GameCanvas canvas;
	private ErsBox[][] boxes = new ErsBox[BOXES_ROWS][BOXES_COLS];
	private int style, y, x, level;
	private boolean pausing = false, moving = true;

	/*
	 * 构造一个函数,产生一个特定的块 style为块的样式,对应STYLES中的某一个 y起始位置,左上角在canvas中的坐标行
	 * x起始位置,左上角在canvas中的坐标列 level游戏等级控制下降速度 canvas面板
	 */
	public ErsBlock(int style, int y, int x, int level, GameCanvas canvas) {
		this.style = style;
		this.y = y;
		this.x = x;
		this.level = level;
		this.canvas = canvas;

		int key = 0x8000;
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				boolean isColor = ((style & key) != 0);
				boxes[i][j] = new ErsBox(isColor);
				key >>= 1;
			}
		}
		display();
	}

	/*
	 * 线程类的run()函数覆盖,下落块,直到块不能再下落
	 */
	@Override
	public void run() {
		while (moving) {
			try {
				sleep(BETWEEN_LEVELS_DEGRESS_TIME * (RussiaBlocksGame.MAX_LEVEL - level + LEVEL_FLATNESS_GENE));
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
			// 后边的moving是表示在等待的100毫秒间,moving没有被改变
			if (!pausing) {
				moving = (moveTo(y + 1, x) && moving);
			}
		}
	}

	/*
	 * 块左移一格
	 */
	public void moveLeft() {
		// TODO Auto-generated method stub
		moveTo(y, x - 1);
	}

	/*
	 * 块右移一格
	 */
	public void moveRight() {
		// TODO Auto-generated method stub
		moveTo(y, x + 1);
	}

	/**
	 * 块下移一格
	 */
	public void moveDown() {
		// TODO Auto-generated method stub
		moveTo(y + 1, x);
	}

	/*
	 * 块变形
	 */
	public void turnNext() {
		for (int i = 0; i < BLOCK_KIND_NUMBER; i++) {
			for (int j = 0; j < BLOCK_STASTUS_NUMBER; j++) {
				if (STYLES[i][j] == style) {
					int newStyle = STYLES[i][(j + 1) % BLOCK_STASTUS_NUMBER];
					turnTo(newStyle);
					return;
				}
			}
		}
	}

	public void startMove() {
		// TODO Auto-generated method stub
		pausing = false;
		moving = true;

	}

	/*
	 * 暂定块的下落,对应暂停游戏
	 */
	public void pauseMove() {
		// TODO Auto-generated method stub
		pausing = true;
		// moving = false;
	}

	/*
	 * 继续块的下落,对应游戏的继续
	 */
	public void resumeMove() {
		// TODO Auto-generated method stub
		pausing = false;
		moving = true;

	}

	/*
	 * 停止块的下落,对应游戏的停止
	 */
	public void stopMove() {
		// TODO Auto-generated method stub
		pausing = false;
		moving = false;
	}

	/*
	 * 将当前块从画布的对应位置移除,要等到下次重画画布时才能反映出来
	 */
	private void erase() {
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				if (boxes[i][j].isColorBox()) {
					ErsBox box = canvas.getBox(i + y, j + x);
					if (box == null) {
						continue;
					}
					box.setColor(false);
				}
			}
		}
	}

	/*
	 * 让当前块放置在画布的对应位置上,要等到下次重画画布时,才能看见
	 */
	private void display() {
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				if (boxes[i][j].isColorBox()) {
					ErsBox box = canvas.getBox(i + y, j + x);
					if (box == null) {
						continue;
					}
					box.setColor(true);
				}
			}

		}

	}

	/**
	 * 当前块能否移动到newRow/newCol 所指定的位置
	 *
	 * @param newRow int,目的地所在行
	 * @param newCol int,目的地所在列
	 * @return boolean,true-能移动,false-不能移动
	 */
	public boolean isMoveAble(int newRow, int newCol) {
		erase();
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				if (boxes[i][j].isColorBox()) {
					ErsBox box = canvas.getBox(i + newRow, j + newCol);
					if (box == null || (box.isColorBox())) {
						display();
						return false;
					}
				}
			}
		}
		display();
		return true;
	}

	/*
	 * 将当前块移动到newRow/newCol所指定位置 newRow 目的所在行 newCol 目的所在列 boolean, true 能移动,false
	 * 不能移动
	 */
	private synchronized boolean moveTo(int newRow, int newCol) {
		if (!isMoveAble(newRow, newCol) || !moving) {
			return false;
		}

		erase();
		y = newRow;
		x = newCol;

		display();
		canvas.repaint();

		return true;
	}

	/*
	 * 当前块能否变成newStyle所指定的样式,主要考虑 边界,以及被其他块挡住不能移动的情况 newStyle,希望改变的样式 boolean true
	 * 能改变,false不能改变
	 */
	private boolean isTurnAble(int newStyle) {
		int key = 0x80000;
		erase();
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				if ((newStyle & key) != 0) {
					ErsBox box = canvas.getBox(i + y, j + x);
					if (box == null || (box.isColorBox())) {
						display();
						return false;
					}
				}
				key >>= 1;
			}
		}
		display();
		return true;
	}

	/*
	 * 将当前块变成newStyle所指定的块样式 newStyle ,希望改变的样式,对应STYLES中的某一个 true 改变成功,false改变失败
	 */
	private boolean turnTo(int newStyle) {
		// TODO Auto-generated method stub
		if (!isTurnAble(newStyle) || !moving) {
			return false;
		}

		erase();
		int key = 0x8000;
		for (int i = 0; i < boxes.length; i++) {
			for (int j = 0; j < boxes[i].length; j++) {
				boolean isColor = ((newStyle & key) != 0);
				boxes[i][j].setColor(isColor);
				key >>= 1;
			}
		}
		style = newStyle;

		display();
		canvas.repaint();

		return true;
	}

}

6、游戏主类,实现游戏控制

public RussiaBlocksGame(String title) {
		super(title); // 设置标题
		setSize(500, 600); // 设置窗口大小
		setLocationRelativeTo(null); // 设置窗口居中

		creatMenu();
		Container container = getContentPane(); // 创建菜单栏
		container.setLayout(new BorderLayout(6, 0)); // 设置窗口的布局管理器
		canvas = new GameCanvas(20, 15); // 新建游戏画布
		ctrlPanel = new ControlPanel(this); // 新建控制面板
		container.add(canvas, BorderLayout.CENTER); // 左边加上画布
		container.add(ctrlPanel, BorderLayout.EAST); // 右边加上控制面板

		// 注册窗口事件。当点击关闭按钮时,结束游戏,系统退出。
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent we) {
				stopGame();
				System.exit(0);
			}
		});

		// 根据窗口大小,自动调节方格的尺寸
		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent ce) {
				canvas.adjust();
			}
		});

		setVisible(true);
		canvas.adjust();
	}

	/**
	 * 让游戏复位
	 */
	public void reset() { // 画布复位,控制面板复位
		ctrlPanel.setPlayButtonEnable(true);
		ctrlPanel.setPauseButtonEnable(false);
		ctrlPanel.setPauseButtonLabel(true);
		ctrlPanel.setStopButtonEnable(false);
		ctrlPanel.setTurnLevelDownButtonEnable(true);
		ctrlPanel.setTurnLevelUpButtonEnable(true);
		miPlay.setEnabled(true);
		miPause.setEnabled(false);
		miResume.setEnabled(false);
		miStop.setEnabled(false);
		ctrlPanel.reset();
		canvas.reset();
	}

	/**
	 * 判断游戏是否还在进行
	 *
	 * @return boolean,true -还在运行,false-已经停止
	 */
	public boolean isPlaying() {
		return playing;
	}

	/**
	 * 得到当前活动的块
	 *
	 * @return ErsBlock,当前活动块的引用
	 */
	public ErsBlock getCurBlock() {
		return block;
	}

	/**
	 * 得到当前画布
	 *
	 * @return GameCanvas,当前画布的引用
	 */
	public GameCanvas getCanvas() {
		return canvas;
	}

	/**
	 * 开始游戏
	 */
	public void playGame() {
		play();
		ctrlPanel.setPlayButtonEnable(false);
		ctrlPanel.setPauseButtonEnable(true);
		ctrlPanel.setPauseButtonLabel(true);
		ctrlPanel.setStopButtonEnable(true);
		ctrlPanel.setTurnLevelDownButtonEnable(false);
		ctrlPanel.setTurnLevelUpButtonEnable(false);
		miStop.setEnabled(true);
		miTurnHarder.setEnabled(false);
		miTurnEasier.setEnabled(false);
		ctrlPanel.requestFocus(); // 设置焦点
	}

	/**
	 * 游戏暂停
	 */
	public void pauseGame() {
		if (block != null) {
			block.pauseMove();
		}
		ctrlPanel.setPlayButtonEnable(false);
		ctrlPanel.setPauseButtonLabel(false);
		ctrlPanel.setStopButtonEnable(true);
		miPlay.setEnabled(false);
		miPause.setEnabled(false);
		miResume.setEnabled(true);
		miStop.setEnabled(true);
	}

	/**
	 * 让暂停中的游戏继续
	 */
	public void resumeGame() {
		if (block != null) {
			block.resumeMove();
		}
		ctrlPanel.setPlayButtonEnable(false);
		ctrlPanel.setPauseButtonEnable(true);
		ctrlPanel.setPauseButtonLabel(true);
		miPause.setEnabled(true);
		miResume.setEnabled(false);
		ctrlPanel.requestFocus();
	}

	/**
	 * 用户停止游戏
	 */
	public void stopGame() {
		playing = false;
		if (block != null) {
			block.stopMove();
		}
		ctrlPanel.setPlayButtonEnable(true);
		ctrlPanel.setPauseButtonEnable(false);
		ctrlPanel.setPauseButtonLabel(true);
		ctrlPanel.setStopButtonEnable(false);
		ctrlPanel.setTurnLevelDownButtonEnable(true);
		ctrlPanel.setTurnLevelUpButtonEnable(true);
		miPlay.setEnabled(true);
		miPause.setEnabled(false);
		miResume.setEnabled(false);
		miStop.setEnabled(false);
		miTurnHarder.setEnabled(true);
		miTurnEasier.setEnabled(true);
		reset();// 重置画布和控制面板
	}

	/**
	 * 得到游戏者设置的难度
	 *
	 * @return int ,游戏难度1-MAX_LEVEL
	 */
	public int getLevel() {
		return ctrlPanel.getLevel();
	}

	/**
	 * 用户设置游戏难度
	 *
	 * @param level int ,游戏难度1-MAX_LEVEL
	 */
	public void setLevel(int level) {
		if (level < 11 && level > 0) {
			ctrlPanel.setLevel(level);
		}
	}

	/**
	 * 得到游戏积分
	 *
	 * @return int,积分
	 */
	public int getScore() {
		if (canvas != null) {
			return canvas.getScore();
		}
		return 0;
	}

	/**
	 * 得到自上次升级以来的游戏积分,升级以后,此积分清零
	 *
	 * @return int,积分
	 */
	public int getScoreForLevelUpdate() {
		if (canvas != null) {
			return canvas.getScoreForLevelUpdate();
		}
		return 0;
	}

	/**
	 * 当积分累积到一定数值时,升一次级
	 *
	 * @return Boolean,true-update succeed,false-update fail
	 */
	public boolean levelUpdate() {
		int curLevel = getLevel();
		if (curLevel < MAX_LEVEL) {
			setLevel(curLevel + 1);
			canvas.resetScoreForLevelUpdate();
			return true;
		}
		return false;
	}

	/**
	 * 游戏开始
	 */
	private void play() {
		reset();
		playing = true;
		Thread thread = new Thread(new Game());// 启动游戏线程
		thread.start();
	}

	/**
	 * 报告游戏结束了
	 */
	private void reportGameOver() {
		new gameOverDialog(this, "俄罗斯方块", "游戏结束,您的得分为" + canvas.getScore());
	}

	/**
	 * 一轮游戏过程,实现了Runnable接口 一轮游戏是一个大循环,在这个循环中,每隔100毫秒, 检查游戏中的当前块是否已经到底了,如果没有,
	 * 就继续等待。如果到底了,就看有没有全填满的行, 如果有就删除它,并为游戏者加分,同时随机产生一个新的当前块并让它自动落下。
	 * 当新产生一个块时,先检查画布最顶上的一行是否已经被占了,如果是,可以判断Game Over 了。
	 */
	private class Game implements Runnable {
		@Override
		public void run() {
			int col = (int) (Math.random() * (canvas.getCols() - 3));
			int style = ErsBlock.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];

			while (playing) {
				if (block != null) { // 第一次循环时,block为空
					if (block.isAlive()) {
						try {
							Thread.currentThread();
							Thread.sleep(500);
						} catch (InterruptedException ie) {
							ie.printStackTrace();
						}
						continue;
					}
				}

				checkFullLine(); // 检查是否有全填满的行

				if (isGameOver()) {
					reportGameOver();
					miPlay.setEnabled(true);
					miPause.setEnabled(false);
					miResume.setEnabled(false);
					miStop.setEnabled(false);
					ctrlPanel.setPlayButtonEnable(true);
					ctrlPanel.setPauseButtonLabel(false);
					ctrlPanel.setStopButtonEnable(false);
					return;
				}

				block = new ErsBlock(style, -1, col, getLevel(), canvas);
				block.start();

				col = (int) (Math.random() * (canvas.getCols() - 3));
				style = ErsBlock.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)];

				ctrlPanel.setTipStyle(style);
			}
		}

		// 检查画布中是否有全填满的行,如果有就删之
		public void checkFullLine() {
			for (int i = 0; i < canvas.getRows(); i++) {
				int row = -1;
				boolean fullLineColorBox = true;
				for (int j = 0; j < canvas.getCols(); j++) {
					if (!canvas.getBox(i, j).isColorBox()) {
						fullLineColorBox = false;
						break;
					}
				}
				if (fullLineColorBox) {
					row = i--;
					canvas.removeLine(row);
				}
			}
		}

		// 根据最顶行是否被占,判断游戏是否已经结束了
		// @return boolean ,true-游戏结束了,false-游戏未结束
		private boolean isGameOver() {
			for (int i = 0; i < canvas.getCols(); i++) {
				ErsBox box = canvas.getBox(0, i);
				if (box.isColorBox()) {
					return true;
				}
			}
			return false;
		}
	}

	/**
	 * 定义GameOver对话框。
	 */
	@SuppressWarnings("serial")
	private class gameOverDialog extends JDialog implements ActionListener {

		private JButton againButton, exitButton;
		private Border border = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140));

		public gameOverDialog(JFrame parent, String title, String message) {
			super(parent, title, true);
			if (parent != null) {
				setSize(240, 120);
				this.setLocationRelativeTo(parent);
				JPanel messagePanel = new JPanel();
				messagePanel.add(new JLabel(message));
				messagePanel.setBorder(border);
				Container container = this.getContentPane();
				container.setLayout(new GridLayout(2, 0, 0, 10));
				container.add(messagePanel);
				JPanel choosePanel = new JPanel();
				choosePanel.setLayout(new GridLayout(0, 2, 4, 0));
				container.add(choosePanel);
				againButton = new JButton("再玩一局");
				exitButton = new JButton("退出游戏");
				choosePanel.add(new JPanel().add(againButton));
				choosePanel.add(new JPanel().add(exitButton));
				choosePanel.setBorder(border);
			}
			againButton.addActionListener(this);
			exitButton.addActionListener(this);
			this.setVisible(true);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getSource() == againButton) {
				this.setVisible(false);
				reset();
			} else if (e.getSource() == exitButton) {
				stopGame();
				System.exit(0);

			}
		}
	}
发布了6 篇原创文章 · 获赞 7 · 访问量 1663

猜你喜欢

转载自blog.csdn.net/weixin_44480968/article/details/104254030