import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
/**
* 一个2D迷宫游戏.
*
* @author 山
*
*/
public class MazeGame {// 主方法
public static void main(String[] args) {
JFrame frame = new JFrame("迷宫游戏");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MazeGamePanel());
frame.pack();
frame.setVisible(true);
}
}
class MazeGamePanel extends JPanel {// 主面板:显示迷宫以及定义相关操作.
private final int DELAY = 10,CHASEDELAY=3500;//定时器延迟时间,无墙模式追赶者移动延迟时间
private final int checkSizeDefault = 20, widthDefault = 45,
heightDefault = 25, numberOfChasersDefault = 20,
tearDownAllowedDefault = 10;// 默认值
private final int panelWidth = 1024, panelHeight = 750;// 主面板宽,高
private int checkSize, width, height, numberOfChasers, tearDownAllowed;
// 迷宫的单位方格大小(以像素为单位),迷宫的宽度(方格数),迷宫的高度(方格数),追赶者数目,玩家可拆墙次数限制
private Maze maze;// 一个迷宫面板
private JButton tipButton,solve, newMaze, chase, newSure,newCancel,noWalls;
// 解答开关按键,生成新迷宫按键,追赶者开关按键,制造新迷宫确定取消按键,无墙模式按键
private boolean tipControl,solveControl,chaseControl;//开关按键控制:true为目前开启,false为目前关闭
private JLabel help, tip, tearDownAllowedTimes;// 帮助标签,提示标签
private Timer timer;// 定时器:每隔10毫秒就获取当前游戏结果和当前提示.注意:迷宫开始,计时器开始;迷宫停止(指玩家输或赢),计时器停止
// (由于玩家不动也有可能被追赶成功,因此不推荐在每次移动时作出判断)
private JLabel checkSizeLabel, widthLabel, heightLabel,
numberOfChasersLabel, tearDownAllowedLabel;// 滑动条提示
private JSlider checkSizeSlider, widthSlider, heightSlider,
numberOfChasersSlider, tearDownAllowedSlider;// 滑动条
private JPanel mazeMaker;// 迷宫制造者:通过滑动条制造迷宫.仅当玩家点击"制造新迷宫"或输或赢时才可见
private JScrollPane mazeContainer;//存放迷宫面板的滚动窗格
private boolean noWallsControl;//无墙模式控制
public MazeGamePanel() {
checkSize = checkSizeDefault;// 初始化一个迷宫:方格边长:20像素
width = widthDefault;// 宽35个方格
height = heightDefault;// 高25个方格.即迷宫面板大小为500*700
numberOfChasers = numberOfChasersDefault;// 默认两个追赶者
tearDownAllowed = tearDownAllowedDefault;// 默认不能拆墙
maze = new Maze(checkSize, width, height, numberOfChasers,
tearDownAllowed);// 根据上面的设置来初始化迷宫
tipButton=new JButton("开启/关闭 提示");
tipControl=false;
chase = new JButton("开启/关闭 追赶者");
chaseControl=true;
solve = new JButton("开启/关闭 答案");
solveControl=false;
newMaze = new JButton("制造新迷宫");
noWalls=new JButton("无墙模式");
noWallsControl=false;//默认有墙模式
newSure = new JButton("确定");
newCancel = new JButton("取消");
help = new JLabel(maze.help()+ "请 按 方 向 建 移 动. 按 W,S,A,D 拆除 上,下,左,右 墙.");
//按键功能与Maze类无关
tip = new JLabel(maze.currentTip());
tearDownAllowedTimes = new JLabel("剩余可拆墙次数:"
+ maze.tearDownAllowedTimes());
timer = new Timer(DELAY, new TimerListener());
timer.start();// 注意:迷宫开始,计时器开始;迷宫停止(指玩家输或赢),计时器停止
maze.addKeyListener(new KeyBoardListener());// 迷宫面板添加键盘监听器
maze.setFocusable(true);
checkSizeSlider = new JSlider(JSlider.HORIZONTAL, 5, 50,
checkSizeDefault);
checkSizeSlider.setMajorTickSpacing(5);
checkSizeSlider.setPaintTicks(true);
checkSizeSlider.setPaintLabels(true);
checkSizeSlider.setAlignmentX(Component.LEFT_ALIGNMENT);
widthSlider = new JSlider(JSlider.HORIZONTAL, 10, 50, widthDefault);
widthSlider.setMajorTickSpacing(5);
widthSlider.setPaintTicks(true);
widthSlider.setPaintLabels(true);
widthSlider.setAlignmentX(Component.LEFT_ALIGNMENT);
heightSlider = new JSlider(JSlider.HORIZONTAL, 10, 40, heightDefault);
heightSlider.setMajorTickSpacing(5);
heightSlider.setPaintTicks(true);
heightSlider.setPaintLabels(true);
heightSlider.setAlignmentX(Component.LEFT_ALIGNMENT);
numberOfChasersSlider = new JSlider(JSlider.HORIZONTAL, 0, 50,
numberOfChasersDefault);
numberOfChasersSlider.setMajorTickSpacing(5);
numberOfChasersSlider.setPaintTicks(true);
numberOfChasersSlider.setPaintLabels(true);
numberOfChasersSlider.setAlignmentX(Component.LEFT_ALIGNMENT);
tearDownAllowedSlider = new JSlider(JSlider.HORIZONTAL, -1, 30,
tearDownAllowedDefault);
tearDownAllowedSlider.setMajorTickSpacing(5);
tearDownAllowedSlider.setPaintTicks(true);
tearDownAllowedSlider.setPaintLabels(true);
tearDownAllowedSlider.setAlignmentX(Component.LEFT_ALIGNMENT);
maze.setPreferredSize(new Dimension(panelWidth,panelHeight));
//用setPreferredSize设置加入到滚动窗格的面板的大小才可以使滚动窗格有效
mazeContainer=new JScrollPane(maze);//迷宫面板放到滚动窗格中
mazeContainer.setEnabled(false);//这样可以使JScrollPane不响应键盘,只响应鼠标.这样走迷宫会好一点
SliderListener listener = new SliderListener();
checkSizeSlider.addChangeListener(listener);
widthSlider.addChangeListener(listener);
heightSlider.addChangeListener(listener);
numberOfChasersSlider.addChangeListener(listener);
tearDownAllowedSlider.addChangeListener(listener);
checkSizeLabel = new JLabel("小方格边长(以像素为单位):" + checkSizeDefault);
widthLabel = new JLabel("宽度(方格数):" + widthDefault);
heightLabel = new JLabel("高度(方格数):" + heightDefault);
numberOfChasersLabel = new JLabel("追赶者数目(可设为0):"
+ numberOfChasersDefault);
tearDownAllowedLabel = new JLabel("可拆墙限制次数(设为-1则不限次数,设为0则不能拆墙):"
+ tearDownAllowedDefault);
ButtonListener bListener = new ButtonListener();
chase.addActionListener(bListener);
solve.addActionListener(bListener);
tipButton.addActionListener(bListener);
newMaze.addActionListener(bListener);
noWalls.addActionListener(bListener);
newSure.addActionListener(bListener);
newCancel.addActionListener(bListener);// 添加按键监听器
JLabel title=new JLabel("迷 宫 制 造 者");
mazeMaker = new JPanel();
mazeMaker.setLayout(new BoxLayout(mazeMaker, BoxLayout.Y_AXIS));
mazeMaker.add(title);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 50)));
mazeMaker.add(checkSizeLabel);
mazeMaker.add(checkSizeSlider);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 30)));
mazeMaker.add(widthLabel);
mazeMaker.add(widthSlider);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 30)));
mazeMaker.add(heightLabel);
mazeMaker.add(heightSlider);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 30)));
mazeMaker.add(numberOfChasersLabel);
mazeMaker.add(numberOfChasersSlider);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 30)));
mazeMaker.add(tearDownAllowedLabel);
mazeMaker.add(tearDownAllowedSlider);
JPanel controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.X_AXIS));
controls.add(newSure);
controls.add(newCancel);
mazeMaker.add(Box.createRigidArea(new Dimension(0, 50)));
mazeMaker.add(controls);
mazeMaker.add(Box.createRigidArea(new Dimension(0, panelHeight)));
// 加上以上语句,在显示mazeMaker的时候就不会显示到迷宫,比较美观
mazeMaker.setPreferredSize(new Dimension(panelWidth, panelHeight));
mazeMaker.setVisible(false);// 仅当玩家点击"制造新迷宫"或输或赢时才可见
JPanel labels = new JPanel();
labels.setLayout(new BoxLayout(labels, BoxLayout.Y_AXIS));
labels.add(tip);
labels.add(tearDownAllowedTimes);
labels.add(help);
JPanel controlPanel = new JPanel();// 控制面板
controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS));
controlPanel.add(tipButton);
controlPanel.add(chase);
controlPanel.add(solve);
controlPanel.add(newMaze);
controlPanel.add(noWalls);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));