到IDEA中创建一个宽603像素,高680像素的游戏主界面
到IDEA中创建一个宽488像素,高430像素的登录界面
到IDEA中创建一个宽488像素,高500像素的注册界面
解题思路分析:因为程序主要分为三块(即游戏界面、登陆界面、注册界面),每一个界面内又有很多操作,需要写很多代码,因此要把三个界面分开写在三个class当中,而不是只写在一个main方法中,这样也有利于以后的代码找错和维护。在以后的开发过程中,main方法通常作为程序的启动入口,里面是不会有逻辑代码的。
创建main方法的操作如下:
在IDEA中右击src--> new --> javaclass --> 新建类名为App --> 在App类中书写main方法
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
//注意这个继承的操作!!!
public class GameJFrame extends JFrame {
//JFrame 界面,窗体
//它的子类也是界面,窗体
//规定:GameJFrame这个界面表示的就是游戏的主界面(所以需要继承JFrame)
//以后跟游戏相关的所有逻辑都写在这个类中
public GameJFrame(){
//JavaBean类描述界面的属性(宽 高) 行为(是否显示窗口)
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setVisible(true); //设置窗口是否显示 true为显示 false为隐藏
}
}
package YouXiUI;
/**登录界面的业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码
* 生成一个验证码
* 获取用户输入放入验证码
* 比较用户名、密码、验证码等等
*/
import javax.swing.*;
public class LoginJFrame extends JFrame {
//LoginJFrame表示登录界面
//以后所有跟登录有关的代码,都写在这里
//构造方法的作用,就是给对象设置默认属性值
//设置默认属性值的时候,把设置的代码写在构造方法里面
public LoginJFrame(){
//在创建登陆界面的时候,同时给这些界面设置一些信息
//比如:宽、高、直接展示出来
this.setSize(488,430); //this代表当前对象(当前的LoginJFrame对象)
this.setVisible(true);
}
}
package YouXiUI;
/**注册界面业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码(两次)
* 比较两次的密码是否一致
* 判断当前用户是否已经注册等等
*/
import javax.swing.*;
public class RegisterJFrame extends JFrame {
//跟注册界面有关的代码,都写在这个界面中
//利用构造方法设置初始化默认值
public RegisterJFrame(){
this.setSize(488,500);
this.setVisible(true);
}
}
import YouXiUI.GameJFrame;
import YouXiUI.LoginJFrame;
import YouXiUI.RegisterJFrame;
public class App {
//开发过程中,main方法为程序的启动入口
public static void main(String[] args) {
//如果我们想要开启一个界面,就创建谁的对象就可以了
new LoginJFrame(); // 创建登录界面对象
new RegisterJFrame(); //创建注册界面
new GameJFrame(); //创建游戏的主界面
}
}
2.1、创建主界面2
用继承改写上述界面,并思考用继承改写的好处
创建主界面2代码如下:
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
//注意这个继承的操作!!!
public class GameJFrame extends JFrame {
//JFrame 界面,窗体
//它的子类也是界面,窗体
//规定:GameJFrame这个界面表示的就是游戏的主界面(所以需要继承JFrame)
//以后跟游戏相关的所有逻辑都写在这个类中
public GameJFrame(){
//JavaBean类描述界面的属性(宽 高) 行为(是否显示窗口)
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
/**设置界面置顶(即设置页面始终悬浮在其他页面之上)
* 为true时该窗口会有“任何情况下都会悬浮在其他窗口之上”的效果
* 为false时,点击其他界面时,该窗口就会被其他界面遮挡住
*/
this.setAlwaysOnTop(true);
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
/**设置关闭模式(设置程序结束运行的方式)
* DO_NOTHING_ON_CLOSE = 0 什么都不做的默认窗口关闭工作(任何操作都关不了窗口)
* HIDE_ON_CLOSE = 1 windows默认窗口关闭操作,窗口会被关闭,但程序不会结束运行
* DISPOSE_ON_CLOSE = 2 开启多个界面之后,只有关闭所有开启的窗口,程序才会结束(用2时,需要所有的界面都做这样的设置,才会有效果)
* EXIT_ON_CLOSE = 3 只要关闭一个界面,所有界面都会关闭,且程序会结束运行
* 可以用 this.setDefaultCloseOperation(1); //1可以替换成0、2、3
* 也可以利用WindowConstants去调用对应的常量值,如下:(DISPOSE_ON_CLOSE可以替换成其他对应的英文)
* this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
*/
this.setDefaultCloseOperation(3);
this.setVisible(true); //设置窗口是否显示 true为显示 false为隐藏,建议写在最后
}
}
package YouXiUI;
/**登录界面的业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码
* 生成一个验证码
* 获取用户输入放入验证码
* 比较用户名、密码、验证码等等
*/
import javax.swing.*;
public class LoginJFrame extends JFrame {
//LoginJFrame表示登录界面
//以后所有跟登录有关的代码,都写在这里
//构造方法的作用,就是给对象设置默认属性值
//设置默认属性值的时候,把设置的代码写在构造方法里面
public LoginJFrame(){
//在创建登陆界面的时候,同时给这些界面设置一些信息
//比如:宽、高、直接展示出来
this.setSize(488,430); //this代表当前对象(当前的LoginJFrame对象)
this.setTitle("拼图 登录"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
package YouXiUI;
/**注册界面业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码(两次)
* 比较两次的密码是否一致
* 判断当前用户是否已经注册等等
*/
import javax.swing.*;
public class RegisterJFrame extends JFrame {
//跟注册界面有关的代码,都写在这个界面中
//利用构造方法设置初始化默认值
public RegisterJFrame(){
this.setSize(488,500);
this.setTitle("拼图 注册"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
import YouXiUI.GameJFrame;
import YouXiUI.LoginJFrame;
import YouXiUI.RegisterJFrame;
public class App {
//开发过程中,main方法为程序的启动入口
public static void main(String[] args) {
//如果我们想要开启一个界面,就创建谁的对象就可以了
new LoginJFrame(); // 创建登录界面对象
new RegisterJFrame(); //创建注册界面
new GameJFrame(); //创建游戏的主界面
}
}
分析过程图1
分析过程图2
分析过程图3
实现代码如下:
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
public class GameJFrame extends JFrame {
//构造方法
public GameJFrame(){
//Ctrl + Alt + M 提取代码形成方法
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
this.setVisible(true); //让界面显示出来,建议写在最后
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
}
}
package YouXiUI;
/**登录界面的业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码
* 生成一个验证码
* 获取用户输入放入验证码
* 比较用户名、密码、验证码等等
*/
import javax.swing.*;
public class LoginJFrame extends JFrame {
public LoginJFrame(){
this.setSize(488,430); //this代表当前对象(当前的LoginJFrame对象)
this.setTitle("拼图 登录"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
package YouXiUI;
/**注册界面业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码(两次)
* 比较两次的密码是否一致
* 判断当前用户是否已经注册等等
*/
import javax.swing.*;
public class RegisterJFrame extends JFrame {
public RegisterJFrame(){
this.setSize(488,500);
this.setTitle("拼图 注册"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
import YouXiUI.GameJFrame;
import YouXiUI.LoginJFrame;
import YouXiUI.RegisterJFrame;
public class App {
//开发过程中,main方法为程序的启动入口
public static void main(String[] args) {
//如果我们想要开启一个界面,就创建谁的对象就可以了
//new LoginJFrame(); // 创建登录界面对象
//new RegisterJFrame(); //创建注册界面
new GameJFrame(); //创建游戏的主界面
}
}
说明1:
说明2:
找到下载好的image文件夹,然后ctrl+C,然后打开IDEA,在IDEA中选中模块名(切记:一定要选中模块名,不然会出错),然后ctrl+V,点击OK就可以了。
说明3:
坐标以左上角为原点,向右为X轴正方方向,向下为Y轴正方向,图片的所在位置实际上是指图片左上角的点所在的坐标位置,例如下面图片,如果图片的位置设置为(0,0),则图片就会在左上角显示。
说明4:
窗口一共分为三个部分,如下图所示,JFrame只是一个大的架子,最下面的第三部分才是用来装载所有组件的(组件可以为图片、文字、按钮、进度条),第三部分是一个隐藏的容器,把需要显示的图片添加到隐藏容器中,如果对添加的图片没有特殊要求,图片就会默认添加到中间位置。利用setLayout(null)可以取消该默认方式,达到自由设置位置的效果。如果要取消默认。在创建窗口的时候就要书写setLayout(null)方法。取消隐藏容器中的居中默认方式后,里面添加的组件才会按照XY轴的形式来进行添加。
添加两个哈士奇拼图小图片代码如下:
(注意:实现此功能的时候,只需要修改主界面的代码,其他代码不需要修改)
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
public class GameJFrame extends JFrame {
//构造方法
public GameJFrame(){
//Ctrl + Alt + M 提取代码形成方法
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
//初始化图片
//直接书写,会报错,然后利用alt+enter,然后选择Create menthod等等的那个选项,点击回车
//就会自动生成下面的private void initImage() { }方法
initImage();
this.setVisible(true); //让界面显示出来,建议写在最后
}
//初始化图片
private void initImage() {
//先创建一个图片ImageIcon的对象
/**ImageIcon icon = new ImageIcon("图片路径"); 说明
* 括号里面的参数是需要添加的图片的地址
* 找到IDEA左边的项目下的image,
* image -> animal -> animal3 -> 3.jpg -> 右击3.jpg -> Copy -> Copy Path -> 选中Absolute Path并点击即可完成路径复制
* 将复制的路径粘贴到括号内即可
*/
ImageIcon icon = new ImageIcon("D:\\IDEA2020\\IDEAprocejts\\PinTuYouXi\\image\\animal\\animal3\\1.jpg");
//然后创建一个JLabel的对象(即管理容器)(我们是需要把图片放到管理容器里面的)
JLabel jLabel1 = new JLabel(icon);
//指定图片位置 参数分别为(x坐标,y坐标,图片宽度,图片高度) 单位都是像素
jLabel1.setBounds(0,0,105,105);
//最后把管理容器添加到界面当中
//this.add(jLabel); //图片默认位置为居中正中心
//利用getContentPane()获取到隐藏容器,然后用add()把图片添加到JFrame的隐藏容器中
this.getContentPane().add(jLabel1);
//添加第二张图片
ImageIcon icon2 = new ImageIcon("D:\\IDEA2020\\IDEAprocejts\\PinTuYouXi\\image\\animal\\animal3\\2.jpg");
JLabel jLabel2 = new JLabel(icon2);
jLabel2.setBounds(105,0,105,105);
this.getContentPane().add(jLabel2);
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null); //取消图片默认的居中防放置,只有取消了才会按照XY轴的形式添加组件
}
}
package YouXiUI;
/**登录界面的业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码
* 生成一个验证码
* 获取用户输入放入验证码
* 比较用户名、密码、验证码等等
*/
import javax.swing.*;
public class LoginJFrame extends JFrame {
public LoginJFrame(){
this.setSize(488,430); //this代表当前对象(当前的LoginJFrame对象)
this.setTitle("拼图 登录"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
package YouXiUI;
/**注册界面业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码(两次)
* 比较两次的密码是否一致
* 判断当前用户是否已经注册等等
*/
import javax.swing.*;
public class RegisterJFrame extends JFrame {
public RegisterJFrame(){
this.setSize(488,500);
this.setTitle("拼图 注册"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
import YouXiUI.GameJFrame;
import YouXiUI.LoginJFrame;
import YouXiUI.RegisterJFrame;
public class App {
//开发过程中,main方法为程序的启动入口
public static void main(String[] args) {
//如果我们想要开启一个界面,就创建谁的对象就可以了
//new LoginJFrame(); // 创建登录界面对象
//new RegisterJFrame(); //创建注册界面
new GameJFrame(); //创建游戏的主界面
}
}
添加了拼图游戏中的15张小图片(一个哈士奇的拼图素材)后的代码如下:
(注意:相比于上一步,只改写了GameJFrame的代码)
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
public class GameJFrame extends JFrame {
//构造方法
public GameJFrame(){
//Ctrl + Alt + M 提取代码形成方法
//选中方法 按ctrl+B可以跳转到该方法的代码所在处
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
initImage(); //初始化图片
this.setVisible(true); //让界面显示出来,建议写在最后
}
//初始化图片
private void initImage() {
int number = 1;
//外循环--结合内循环的前提下,从上到下依次添加一行,一共添加四行,Y值依次增加105像素,X值不变
for (int i = 0; i < 4; i++) {
//内循环--在每一行从左到右依次添加一张图片,一共添加四张,X值依次增加105像素,Y值不变
for (int j = 0; j < 4; j++) {
//然后创建一个JLabel的对象(即管理容器) 注意留意路径中的变量number的书写方法
JLabel jLabel = new JLabel(new ImageIcon("D:\\IDEA2020\\IDEAprocejts\\PinTuYouXi\\image\\animal\\animal3\\"+number+".jpg"));
//根据坐标,设置图片的位置
jLabel.setBounds(105*j,105*i,105,105);
//利用getContentPane()获取到隐藏容器,然后用add()把图片添加到JFrame的隐藏容器中
this.getContentPane().add(jLabel);
//添加一次之后number需要自增,表示下一次加载后面的图片
number++;
}
}
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null); //取消图片默认的居中防放置,只有取消了才会按照XY轴的形式添加组件
}
}
游戏主界面添加组件小结
每一张小的图片都是跟一个唯一的数字产生对应关系,分别是1~15和0(空白区域为0)如下图
我们可以把1~15和0,放入数组容器中,然后在容器中打乱顺序,然后每4个数放入一个单独的一维数组当中,再把4个一维数组放入一个二维数组当中,方便管理。如下图:
在继续开发这个小游戏之前,需要做一个小练习,来熟悉一下开发这个游戏需要用到的技术
小练习:打乱一维数组中的数据
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
要求:打乱一维数组中的数据,并按照4个一组的方式添加到二维数组中。
package TEST;
import java.util.Random;
public class Test {
public static void main(String[] args) {
//1、定义一个一维数组
int[] tempArr ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//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;
}
//遍历数组,查看打乱顺序后的效果
for (int i = 0; i < tempArr.length; i++) {
System.out.print(tempArr[i] + " ");
}
System.out.println();
//创建一个二维数组
int[][] date = new int[4][4];
//给二维数组添加数据
/*//方法1:
//遍历一维数组tempArr得到每一个元素,把每一个元素依次添加到二维数组当中
for (int i = 0; i < tempArr.length; i++) {
//在i依次增加的过程中date的右下标依次为
// i为0~3时:[0][0] [0][1] [0][2] [0][3]
// i为4~7时:[1][0] [1][1] [1][2] [1][3]
// i为8~11时:[2][0] [2][1] [2][2] [2][3]
// i为12~15时:[3][0] [3][1] [3][1] [3][3]
date[i/4][i%4] = tempArr[i];
}*/
//方法2:
//遍历二维数组,然后给里面的每一个数据赋值
int index02 = 0;
for (int i = 0; i < date.length; i++) {
for (int j = 0; j < date[i].length; j++) {
//等式左边依次为二维数组的每一个元素(由于嵌套循环的存在),等式右边依次为一维数组的每个元素(由于计数器index02的存在)
date[i][j] = tempArr[index02];
index02++;
}
}
//打印添加到二维数组之后的效果
for (int i = 0; i < date.length; i++) {
for (int j = 0; j < date[i].length; j++) {
System.out.print(date[i][j]+" ");
}
System.out.println();
}
}
}
下面我们继续开发小游戏,对游戏中的图片进行打乱。
(注意:在之前的基础上修改了GameJFrame的代码,其他模块代码不变)
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
import java.util.Random;
public class GameJFrame extends JFrame {
//创建一个二维数组
//目的:用来管理数据。加载图片的时候,会根据二维数组中的数据进行加载
//因为初始化数据时,初始化图片时都会用到这个二维数组,所以把二维数组定义在成员变量的位置
int[][] date = new int[4][4];
//构造方法
public GameJFrame(){
//Ctrl + Alt + M 提取代码形成方法
//选中方法 按ctrl+B可以跳转到该方法的代码所在处
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
initDate(); //初始化数据(打乱)
initImage(); //初始化图片(根据打乱之后的结果去加载图片)
this.setVisible(true); //让界面显示出来,建议写在最后
}
//初始化数据(打乱)
private void initDate() {
//1、定义一个一维数组
int[] tempArr ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//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、给二维数组添加数据
for (int i = 0; i < tempArr.length; i++) {
date[i/4][i%4] = tempArr[i];
}
}
//初始化图片
//由于二维数组已经创建好,所以添加图片的时候,就需要按照二维数组中管理的数据进行添加图片了
//因此之前的number就不需要了,就u、需要删掉了
private void initImage() {
//外循环--结合内循环的前提下,从上到下依次添加一行,一共添加四行,Y值依次增加105像素,X值不变
for (int i = 0; i < 4; i++) {
//内循环--在每一行从左到右依次添加一张图片,一共添加四张,X值依次增加105像素,Y值不变
for (int j = 0; j < 4; j++) {
//获取当前要加载图片的序号,date[i][j]的结果是这个位置上对应的数据值
int num = date[i][j];
//然后创建一个JLabel的对象(即管理容器)
JLabel jLabel = new JLabel(new ImageIcon("D:\\IDEA2020\\IDEAprocejts\\PinTuYouXi\\image\\animal\\animal3\\"+num+".jpg"));
//根据坐标,设置图片的位置
jLabel.setBounds(105*j,105*i,105,105);
//利用getContentPane()获取到隐藏容器,然后用add()把图片添加到JFrame的隐藏容器中
this.getContentPane().add(jLabel);
}
}
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null); //取消图片默认的居中防放置,只有取消了才会按照XY轴的形式添加组件
}
}
事件是可以被组件识别的操作。当你对组件干了某件事情之后,就会执行对应的代码。
事件源:通常是指产生事件的组件。例如:按钮、图片、窗体等等
事件:对组件进行的操作。例如:鼠标单击、鼠标划入等等
绑定监听:当事件源上发生了某个事件,监听器就会做出相应的处理,执行某段代码。
常用的三个监听如下:
动作监听实现的两种方式:
方式1:匿名内部类的实现方式
package TEST;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test01 {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(603,680);//设置界面宽高
jFrame.setTitle("事件演示01");
jFrame.setAlwaysOnTop(true);//设置界面置顶
jFrame.setLocationRelativeTo(null);//设置界面居中
jFrame.setDefaultCloseOperation(3);
jFrame.setLayout(null);//取消组件居中放置
//创建一按钮对象
JButton jtb = new JButton("点我啊");
//设置位置和宽高
jtb.setBounds(0,0,100,50);
/**给按钮添加监听动作
* jtb:组件对象,表示要给哪个组件添加对象
* addActionListener:表示我要给组件添加哪个监听事件(这里添加的是动作监听,包含鼠标左键点击、空格)
* 参数:表示事件被触发之后要执行的代码
*/
/**
* 在实际开发当中,每一个按钮的业务逻辑不一样,所以我们书写的MyActionListener只能被
* 用到一次,只能被这个jtb按钮使用,其他的按钮用不了这个业务逻辑。当一个接口的实现类
* 只能被用一次的时候,我们就没必要单独定义这个类了,此时可以用匿名内部类去简化代
* 码,省去了定义类的过程。
*/
jtb.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("达咩~不要点我哟~");
}
});
//不要忘了把按钮添加到界面当中
jFrame.getContentPane().add(jtb);
jFrame.setVisible(true);
}
}
方式2:用本界面继承JFrame,调用ActionListener接口,把重写的方法写在本类当中,然后在传递的时候不用再new了,直接用this表示本类的对象就可以了。代码如下:
package TEST;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
//继承JFrame是为了创建窗口,调用ActionListener接口是为了给按钮设置监听
public class MyJFrame extends JFrame implements ActionListener {
//创建一个按钮对象
JButton jtb1 = new JButton("点我啊");
//创建一个按钮对象
JButton jtb2 = new JButton("再点我啊");
//构造方法
public MyJFrame(){
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null);
jtb1.setBounds(0,0,100,50);
//给按钮添加事件
//括号中的this表示的是本类的对象,作用是监听后让执行本类(MyJFrame类)中的代码
jtb1.addActionListener(this);
jtb2.setBounds(100,0,100,50);
//给按钮添加事件
jtb2.addActionListener(this);
//把按钮添加到界面当中
this.getContentPane().add(jtb1);
this.getContentPane().add(jtb2);
//让整个界面显现出来
this.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
//对当前按钮进行判断
//获取当前被操作的那个按钮对象
Object source = e.getSource();
//
if(source == jtb1){//让按钮变大
jtb1.setSize(200,200);
} else if(source == jtb2){//更改按钮的位置为随机位置
Random r = new Random();
jtb2.setLocation(r.nextInt(500),r.nextInt(500));
}
}
}
package TEST;
public class Test {
public static void main(String[] args) {
new MyJFrame();
}
}
分为四类:划入动作,按下动作、松开动作、划出动作。
按下动作和松开动作归为一组,称为单击动作。
实践代码如下:
package TEST;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
//继承JFrame是为了创建窗口,调用MouseListener接口是为了给按钮设置鼠标监听
//调用接口的时候,需要重写接口中的所有方法,利用alt+回车的快捷方式书写
public class MyJFrame extends JFrame implements MouseListener {
//创建一个按钮对象
JButton jtb1 = new JButton("点我啊");
//构造方法
public MyJFrame(){
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null);
jtb1.setBounds(0,0,100,50);
//给按钮绑定鼠标事件,参数this表示执行本类中的代码(即执行本类中的重写的方法)
jtb1.addMouseListener(this);
//把按钮添加到界面当中
this.getContentPane().add(jtb1);
//让整个界面显现出来
this.setVisible(true);
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("单击");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("按下不松");
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("松开");
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("划入");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("划出");
}
}
package TEST;
public class Test {
public static void main(String[] args) {
new MyJFrame();
}
}
鼠标监听机制的方法摘要:
实践代码如下:
package TEST;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
//继承JFrame是为了创建窗口,调用MouseListener接口是为了给按钮设置鼠标监听
//调用接口的时候,需要重写接口中的所有方法,利用alt+回车的快捷方式书写
public class MyJFrame extends JFrame implements KeyListener {
//构造方法
public MyJFrame(){
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null);
//给整个窗体添加键盘监听
//调用者this:本类对象,当前的界面对象,表示我要给当前整个界面添加监听
//addKeyListener:表示要给本界面添加键盘监听
//参数this:当事件被触发后,会执行本类中的对应代码(即执行本类中重写的方法)
this.addKeyListener(this);
//让整个界面显现出来
this.setVisible(true);
}
@Override
public void keyTyped(KeyEvent e) {
}
/**小细节
* 细节1:如果我们按下一个按键没有松开,那么会重复调用keyPressed方法
* 细节2:键盘里面那么多按键,如何进行区分? 答:每一个按键都有一个编号与之对应
*/
@Override
public void keyPressed(KeyEvent e) {
System.out.println("按下不松");
}
@Override
public void keyReleased(KeyEvent e) {
System.out.println("松开按键");
//获取键盘上每一个按键的编号
int code = e.getKeyCode();
//System.out.println(code); 打印按下的按键对应的编号
if(code == 65){
System.out.println("现在按的是A");
} else if(code == 66){
System.out.println("现在按的是B");
}
}
}
package TEST;
public class Test {
public static void main(String[] args) {
new MyJFrame();
}
}
图片美化业务逻辑:
1、让15张随机图片整体在中央偏下方显示。
2、给游戏添加一个背景图片。
3、给每一张小图片添加一个小边框。
实现代码如下:
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.util.Random;
public class GameJFrame extends JFrame {
//创建一个二维数组
//目的:用来管理数据。加载图片的时候,会根据二维数组中的数据进行加载
//因为初始化数据时,初始化图片时都会用到这个二维数组,所以把二维数组定义在成员变量的位置
int[][] date = new int[4][4];
//构造方法
public GameJFrame(){
//Ctrl + Alt + M 提取代码形成方法
//ctrl+alt+左键 可以回到我们刚刚查看的地方
//选中方法 按ctrl+B可以跳转到该方法的代码所在处
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
initDate(); //初始化数据(打乱)
initImage(); //初始化图片(根据打乱之后的结果去加载图片)
this.setVisible(true); //让界面显示出来,建议写在最后
}
//初始化数据(打乱)
private void initDate() {
//1、定义一个一维数组
int[] tempArr ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//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、给二维数组添加数据
for (int i = 0; i < tempArr.length; i++) {
date[i/4][i%4] = tempArr[i];
}
}
//初始化图片
//由于二维数组已经创建好,所以添加图片的时候,就需要按照二维数组中管理的数据进行添加图片了
//因此之前的number就不需要了,就u、需要删掉了
private void initImage() {
//外循环--结合内循环的前提下,从上到下依次添加一行,一共添加四行,Y值依次增加105像素,X值不变
for (int i = 0; i < 4; i++) {
//内循环--在每一行从左到右依次添加一张图片,一共添加四张,X值依次增加105像素,Y值不变
for (int j = 0; j < 4; j++) {
//获取当前要加载图片的序号,date[i][j]的结果是这个位置上对应的数据值
int num = date[i][j];
//然后创建一个JLabel的对象(即管理容器)
JLabel jLabel = new JLabel(new ImageIcon("image\\animal\\animal3\\"+num+".jpg"));
//根据坐标,设置图片的位置
//图片美化1:给每一张小图片分别添加83和134像素的位移,让它们做一个整体的偏移,使15张小图片在中央偏下方显示
jLabel.setBounds(105*j + 83,105*i + 134,105,105);
//图片美化3:给小图片添加边框
//BevelBorder斜面边框对象
//0:表示让图片凸起来,英文常量为RAISED 1:表示让图片凹下去,英文常量为LOWERED
jLabel.setBorder(new BevelBorder(1));
//利用getContentPane()获取到隐藏容器,然后用add()把图片添加到JFrame的隐藏容器中
this.getContentPane().add(jLabel);
}
}
/**路径分为两种:(绝对路径和相对路径)
* 绝对路径:一定是从盘符开始的。例如:D:\IDEA2020\IDEAprocejts\PinTuYouXi\image\background.png
* 相对路径:不是从盘符开始的。相对路径是相对当前项目而言。例如:aaa\\bbb 表示在当前项
* 目下,去找aaa文件夹,里面再找bbb文件夹。下面image\\background.png
* 运行之后如果图片消失不显示了,肯定是路径方面有问题,可以各种尝试修改代码中的路径,就可以解决掉这个问题
*/
//图片美化2:添加背景图片
//小细节:先加载的图片在上方,后加载的图片在下方,
//所以得先加载小图片,再加载背景图片,即添加背景图片的代码添加在添加小图片代码的下面
JLabel background = new JLabel(new ImageIcon("image\\background.png"));//利用相对路径优化了图片的路径
background.setBounds(40,40,508,560);
//把背景图片添加到界面当中
this.getContentPane().add(background);
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null); //取消图片默认的居中防放置,只有取消了才会按照XY轴的形式添加组件
}
}
package YouXiUI;
/**注册界面业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码(两次)
* 比较两次的密码是否一致
* 判断当前用户是否已经注册等等
*/
import javax.swing.*;
public class RegisterJFrame extends JFrame {
public RegisterJFrame(){
this.setSize(488,500);
this.setTitle("拼图 注册"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
package YouXiUI;
/**登录界面的业务逻辑
* 获取用户输入的用户名
* 获取用户输入的密码
* 生成一个验证码
* 获取用户输入放入验证码
* 比较用户名、密码、验证码等等
*/
import javax.swing.*;
public class LoginJFrame extends JFrame {
public LoginJFrame(){
this.setSize(488,430); //this代表当前对象(当前的LoginJFrame对象)
this.setTitle("拼图 登录"); //设置界面标题
this.setAlwaysOnTop(true); //设置界面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setVisible(true); //设置窗口为显示
}
}
import YouXiUI.GameJFrame;
import YouXiUI.LoginJFrame;
import YouXiUI.RegisterJFrame;
public class App {
//开发过程中,main方法为程序的启动入口
public static void main(String[] args) {
//如果我们想要开启一个界面,就创建谁的对象就可以了
//new LoginJFrame(); // 创建登录界面对象
//new RegisterJFrame(); //创建注册界面
new GameJFrame(); //创建游戏的主界面
}
}
向上移动实际上就是把空白方块下方的图片上移。
逻辑分析:每一张小图片其实都是跟一个唯一的数字对应,而这些数字都放在了二维数组当中,我们只需要找两个数字在二维数组中的位置,然后做一下数据交换,交换完之后。根据最新的数字加载相应的图片就可以实现图片的移动了。
首先我们要实现的不是上下左右移动。而是需要先给整个界面添加键盘监听事件。因此要让GameJFrame调用键盘监听接口(调用一个接口时,记得要重写里面所有的抽象方法)
代码实现如下:(相比于上一步的代码,只修改了GameJFrame部分的代码)
package YouXiUI;
/**主界面业务逻辑
* 上下左右移动的代码逻辑
* 统计步数的代码逻辑
* 一键通关、查看最终效果、恶搞好友等等
*/
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class GameJFrame extends JFrame implements KeyListener {
int[][] date = new int[4][4];
//记录空白方块在二维数组中的位置
int x = 0;
int y = 0;
//构造方法
public GameJFrame(){
initJFrame(); //调用initJFrame()方法初始化界面
initJMenuBar(); //调用initJMenuBar()方法,初始化菜单
initDate(); //初始化数据(打乱)
initImage(); //初始化图片(根据打乱之后的结果去加载图片)
this.setVisible(true); //让界面显示出来,建议写在最后
}
//初始化数据(打乱)
private void initDate() {
//1、定义一个一维数组
int[] tempArr ={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//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、给二维数组添加数据
for (int i = 0; i < tempArr.length; i++) {
if(tempArr[i] == 0){ //找到0的时候,用x和y记录0的位置
x = i / 4;
y = i % 4;
} else {
date[i/4][i%4] = tempArr[i];
}
}
}
//初始化图片
//根据二维数组中的数字进行图片加载
private void initImage() {
//清空已经出现的所有图片,然后再运行循环,让图片进行重新加载
this.getContentPane().removeAll();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
//获取当前要加载图片的序号,date[i][j]的结果是这个位置上对应的数据值
int num = date[i][j];
//然后创建一个JLabel的对象(即管理容器)
JLabel jLabel = new JLabel(new ImageIcon("image\\animal\\animal3\\"+num+".jpg"));
jLabel.setBounds(105*j + 83,105*i + 134,105,105);
jLabel.setBorder(new BevelBorder(1)); //图片美化3:给小图片添加边框
//利用getContentPane()获取到隐藏容器,然后用add()把图片添加到JFrame的隐藏容器中
this.getContentPane().add(jLabel);
}
}
JLabel background = new JLabel(new ImageIcon("image\\background.png"));//图片美化2:添加背景图片
background.setBounds(40,40,508,560);
//把背景图片添加到界面当中
this.getContentPane().add(background);
//刷新一下加载图片后的界面
this.getContentPane().repaint();
}
//创建初始化菜单的方法
private void initJMenuBar() {
//1、创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//2、创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//3、创建选项下面的条目对象(重新游戏 重新登录 关闭游戏)
JMenuItem replayItem = new JMenuItem("重新游戏");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem closeItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
//4、将每一个选项下面的条目对象添加到选项当中
functionJMenu.add(replayItem);
functionJMenu.add(reLoginItem);
functionJMenu.add(closeItem);
aboutJMenu.add(accountItem);
//5、将菜单里面的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//创建初始化界面的方法
private void initJFrame() {
this.setSize(603,680); //设置窗口的属性(宽 高)
this.setTitle("拼图单机版 v1.0"); //设置界面标题
this.setAlwaysOnTop(true); //设置页面置顶
this.setLocationRelativeTo(null); //设置界面居中,默认情况下页面是在左上角的位置
this.setDefaultCloseOperation(3); //设置程序关闭的方式
this.setLayout(null); //取消图片默认的居中防放置,只有取消了才会按照XY轴的形式添加组件
//给整个界面添加监听事件
this.addKeyListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
//对上、下、左、右进行判断
//左:37 上:38 右:39 下:40
//用code记录用户按下的键盘
int code = e.getKeyCode();
//对code的值进行判断,然后执行对应的操作
if(code == 37){
if(y == 3){
//表示空白方块右面已经没有图片了,空白块就在最右面的一列
return;
}
/**向左移动逻辑:[空白][数字]--->[数字][空白]
* x,y 表示空白方块 x,y+1 表示空白块右边的数字
* 把右边的数字赋值给空白方块,然后让右边的数值为0,
* 交换数据之后,更新一下当前空白块对应的x,y值
*/
date[x][y] = date[x][y+1];
date[x][y+1] = 0;
y++;//空白方块相当于向右移动了,更新一下y的值
//调用方法按照最新的数字加载图片
initImage();
} else if(code == 38){
if(x == 3){
//表示空白方块下面已经没有图片了,空白块就在最下面一行
return;
}
/**向上移动逻辑:[空白] [数字]
* [数字]--->[空白]
* x,y 表示空白方块 x+1,y 表示空白方块下的数字
* 把下边的数字赋值给空白方块,然后让下边的数值为0,
* 交换数据之后,更新一下当前空白块对应的x,y值
*/
date[x][y] = date[x+1][y];
date[x+1][y] = 0;
x++;//空白方块相当于向下移动了,更新一下x的值
//调用方法按照最新的数字加载图片
initImage();
} else if(code == 39){
if(y == 0){
//表示空白方块左面已经没有图片了,空白块就在最左面的一列
return;
}
/**向右移动逻辑:[数字][空白]--->[空白][数字]
* x,y 表示空白方块 x,y-1 表示空白块左边的数字
* 把左边的数字赋值给空白方块,然后让左边的数值为0,
* 交换数据之后,更新一下当前空白块对应的x,y值
*/
date[x][y] = date[x][y-1];
date[x][y-1] = 0;
y--;//空白方块相当于向左移动了,更新一下y的值
//调用方法按照最新的数字加载图片
initImage();
}
else if(code == 40){
if(x == 0){
//表示空白方块上面已经没有图片了,空白块就在最上面一行
return;
}
/**向下移动逻辑:[数字] [空白]
* [空白]--->[数字]
* x,y 表示空白方块 x-1,y 表示空白方块上方的数字
* 把上边的数字赋值给空白方块,然后让上边的数值为0,
* 交换数据之后,更新一下当前空白块对应的x,y值
*/
date[x][y] = date[x-1][y];
date[x-1][y] = 0;
x--;//空白方块相当于向上移动了,更新一下x的值
//调用方法按照最新的数字加载图片
initImage();
}
}
}
上下左右移动业务小结:
1、给本类实现KeyListener接口,并重写所有抽象方法。
2、给整个界面添加键盘监听事件。(因为我们是在游戏界面中按上下左右键去移动的)
3、统计一下空白方块对应的数字0在二维数组中的位置,因为移动方块的本质就是让空白方块对应的数字0跟自己上下左右的数字进行数值交换。
4、在KeyReleased方法当中实现移动的逻辑。(如果用按下按键的方法去写,则如果按住键盘不送,则会一直移动,不符合游戏逻辑,所以用的抬起按键的方法)
5、Bug修复:
(1)、当空白块在最下方时,无法再次进行上移
(2)、当空白块在最上方时,无法再次进行下移。
(3)、当空白块在最左方时,无法再次进行右移。
(4)、当空白块在最右方时,无法再次进行左移。