快捷键
可通过快捷键( ‘B/b’ )的方式直接查看最终效果图
1. 创建游戏主界面( GameJFrame )
跟游戏主界面相关的代码,都写在这个界面中
public class GameJFrame extends JFrame implements KeyListener, ActionListener {
int x=0; //记录空白方块在二维数组中间的位置
int y=0;
String path="image\\animal\\animal3\\"; //定义一个变量,记录当前展示图片的路径
int step=0; //定义变量用来统计步数
//构造函数
public GameJFrame(){
initJFrame(); // 初始化界面
initJMenuBar(); // 初始化菜单
initDate(); //初始化数据(根据打乱之后的结果去加载图片)
initImage(); //初始化图片
this.setVisible(true); //让界面显示出来,建议写在最后
}
}
JFrame是官方提供的一个类,这个类的主要功能是使用该类可以快速的开发出Java界面应用程序(c/s架构),属于java.swing知识体系;它是屏幕上window的对象,能够最大化、最小化、关闭。
KeyListener 是java 中的一个接口,用于接收键盘事件(击键)的侦听器接口。
ActionListener也是java 中的一个接口,为动作事件监听器,当你在点击按钮时希望可以实现一个操作就得用到该接口了。
所以定义GameJFrame类时继承JFrame,并接入KeyListener和ActionListener接口便于后续的操作。
2. 初始化界面 ( initJFrame )
private void initJFrame() { //初始化界面
this.setSize(603,680); //设置界面的宽高
this.setTitle("拼图单机版 v1.0"); //设置界面的标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中
this.setDefaultCloseOperation(3); //设置关闭模式 3模式:关闭其中一个窗口就终止终端的运行
this.setLayout(null); //取消默认的居中放置,只有取消了才会按照XY轴的形式添加组件
this.addKeyListener(this); //给整个界面添加键盘监听事件
}
3. 初始化菜单 ( initJMenuBar )
private void initJMenuBar() { //初始化菜单
//创建整个菜单对象
JMenuBar jMenuBar=new JMenuBar();
//创建菜单上面的俩个选项的对象(功能 关于我们)
JMenu functionJMenu=new JMenu("功能");
JMenu aboutJMenu=new JMenu("关于我们");
//将每一个选项下面的条目添加到选项中
functionJMenu.add(replayItem);
functionJMenu.add(repLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//给条目绑定事件
replayItem.addActionListener(this);
repLoginItem.addActionListener(this);
closeItem.addActionListener(this);
accountItem.addActionListener(this);
//创建选项下面的条目对象 (放入成员变量中)
JMenuItem replayItem=new JMenuItem("重新游戏");
JMenuItem repLoginItem=new JMenuItem("重新登录");
JMenuItem closeItem=new JMenuItem("关闭游戏");
JMenuItem accountItem=new JMenuItem("QQ");
//将菜单里面的俩个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
4. 初始化数据 ( initData )
private void initDate(){ //初始化数据(打乱)
//1. 定义一维数组和二维数组 (二维数组放入成员变量)
int[] tempArr={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int[][] data=new int[4][4]; // 用来管理数据,加载图片的时候,会根据二维数组中的数据进行加载
//2. 打乱数组中的数据的顺序
//遍历数组,得到每一个元素,拿着每一个元素跟随索引上的数据进行交换
Random r=new Random();
for (int i = 0; i < tempArr.length; i++) {
int index=r.nextInt(tempArr.length); //获得到随机索引
//拿着遍历到的每一个数据,跟随机索引上的数据进行交换
int temp=tempArr[i];
tempArr[i]=tempArr[index];
tempArr[index]=temp;
}
//3. 给二维数组添加数据
//遍历一维数组tempArr得到每一个元素,把每一个元素依次添加到二维数组当中
for (int i = 0; i < tempArr.length; i++) {
if(tempArr[i]==0){
x=i/4;
y=i%4;
}
data[i/4][i%4]=tempArr[i];
}
}
5. 初始化图片 ( initImage )
private void initImage() { //初始化图片 添加图片的时候就需要按照二维数组中管理的数据添加图片
this.getContentPane().removeAll(); //清空原本已经出现的所有图片
if(victory()){ //显示胜利图标
JLabel winJLabel=new JLabel(new ImageIcon("image\\win.png"));
winJLabel.setBounds(203,283,197,73);
this.getContentPane().add(winJLabel);
}
JLabel stepCount=new JLabel("步数: " + step);
stepCount.setBounds(50,30,100,20);
this.getContentPane().add(stepCount);
for (int i = 0; i < 4; i++) { //外循环---把内循环重复执行了四次
for (int j = 0; j < 4; j++) { //内循环---表示在一行添加4张图片
int num=data[i][j]; //获取当前要加载图片的序号 //相对路径
ImageIcon icon=new ImageIcon(path+num+".jpg"); //创建一个图片ImageIcon的对象
JLabel jLabel=new JLabel(icon); //创建一个JLabel的对象(管理容器)
jLabel.setBounds(105*j+83,105*i+134,105,105); //指定图片位置 x,y是左上顶点
jLabel.setBorder(new BevelBorder(1)); //给图片添加边框 0:表示让图片凸起来 1:表示让图片凹下去
this.getContentPane().add(jLabel);//把管理容器添加到界面中
}
}
//添加背景图片 //绝对路径
ImageIcon icon1=new ImageIcon("D:\\JAVA\\code\\jigsawgame\\image\\background.png");
JLabel background=new JLabel(icon1);
background.setBounds(40,40,508,560);
this.getContentPane().add(background); //把背景图片添加到界面当中
//刷新图片
this.getContentPane().repaint();
}
6. 键盘监听事件 ( keyPressed 、keyReleased)
//放下不松时会调用这个方法
@Override
public void keyPressed(KeyEvent e) {
int code=e.getKeyCode(); //获取按下的键值
if(code==66){
this.getContentPane().removeAll(); //把界面中所有的图片全部删除
JLabel all=new JLabel(new ImageIcon(path+"all.jpg")); //创建完整图片
all.setBounds(83,134,420,420);
this.getContentPane().add(all); //将完整图片添加到界面中
JLabel background=new JLabel(new ImageIcon("image\\background.png")); //创建背景图片
background.setBounds(40,40,508,560);
this.getContentPane().add(background); //把背景图片添加到界面当中
this.getContentPane().repaint(); //刷新界面
}
}
// 松开按键的时候会调用这个方法
@Override
public void keyReleased(KeyEvent e) {
//判断游戏是否胜利,如果胜利,此方法需要直接结束,不能在执行下面的移动代码了
if(victory()){
return; //结束方法
}
//对上、下、左、右进行判断 左:37 上:38 右:39 下:40
int code=e.getKeyCode(); //获取键盘按下的键值
if(code==37){
if(y==0){
return;
}
data[x][y]=data[x][y-1];
data[x][y-1]=0;
y--;
step++;
initImage(); //调用方法按照最新的数字加载图片
}else if(code==38){
if(x==0){
return;
}
data[x][y]=data[x-1][y];
data[x-1][y]=0;
x--;
step++;
initImage(); //调用方法按照最新的数字加载图片
}else if(code==39){
if(y==3){
return;
}
data[x][y]=data[x][y+1];
data[x][y+1]=0;
y++;
step++;
initImage(); //调用方法按照最新的数字加载图片
}else if(code==40){
if(x==3){
return;
}
data[x][y]=data[x+1][y];
data[x+1][y]=0;
x++;
step++;
initImage(); //调用方法按照最新的数字加载图片
} else if (code==66) { // 65=‘a’键 当长按a键松开时 恢复成打乱时的图片
initImage();
} else if (code==87) { // 87=‘w’键 直接完成拼图
x=3; //将空格图 置放到右下角
y=3;
data=new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initImage();
}
}
7. 按钮监听事件 ( actionPerformed )
@Override
public void actionPerformed(ActionEvent e) {
Object obj=e.getSource(); //获取当前被点击的条目对象
if(obj==replayItem){
System.out.println("重新游戏");
step=0; //步数清零
initDate(); //打乱顺序
initImage(); //重新加载图片
} else if (obj==repLoginItem) {
System.out.println("重新登录");
this.setVisible(false); //关闭当前的游戏界面
new LoginJFrame(); //打开登录界面
} else if (obj==closeItem) {
System.out.println("关闭游戏");
System.exit(0); //直接关闭虚拟机即可
} else if (obj==accountItem) {
System.out.println("QQ");
//创建一个弹框对象
JDialog jDialog=new JDialog();
//创建一个管理图片的容器对象JLabel
JLabel jLabel=new JLabel(new ImageIcon("C:\\Users\\29054\\Desktop\\qq.jpg"));
jLabel.setBounds(0,0,449,449); //设置位置和宽高
jDialog.getContentPane().add(jLabel); //把图片添加到弹框当中 getContentPane()是隐藏容器
jDialog.setSize(500,500); //设置弹框大小
jDialog.setAlwaysOnTop(true); //让弹框置顶
jDialog.setLocationRelativeTo(null); //让弹框居中
jDialog.setModal(true); //弹框不关闭则无法操作下面的界面
jDialog.setVisible(true); //让弹框显示出来
}
}
8. 判断是否胜利 ( victory )
public boolean victory(){
int[][] win={ //定义一个二维数组,存储正确的数据
{1,2,3,4}, // win数组放入成员变量
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
for (int i = 0; i < data.length; i++) {
//data[i]:依次表示每一个一维数组
for (int j = 0; j < data[i].length; j++) {
if(data[i][j]!=win[i][j]){
return false;
}
}
}
return true;
}