目录
一、界面搭建
创建一个模块 模块下创建一个ui的包 用于存放三个图形化界面
在模块下创建一个APP的类 用于游戏的启动入口
界面大小要求:
在ui包下创建主界面gameJFrame
package ui;
import javax.swing.*;
//主界面
public class gameJFrame extends JFrame {
//构造方法
public gameJFrame() {
//设置大小
this.setSize(603, 680); //单位:像素
//界面是默认隐藏的所以要调用setVisible();
this.setVisible(true); //flase为隐藏 true为展示
}
}
在ui包下创建登录界面loginJFrame
package ui;
import javax.swing.*;
//登录界面
public class loginJFrame extends JFrame {
//构造方法
public loginJFrame() {
//设置大小
this.setSize(488, 430);
//显示界面
//界面是默认隐藏的所以要调用setVisible();
this.setVisible(true); //flase为隐藏 true为展示
}
}
在ui包下创建注册界面registerJFrame
package ui;
import javax.swing.*;
//注册界面
public class registerJFrame extends JFrame {
//构造方法
public registerJFrame() {
//设置大小
this.setSize(488, 500);
//显示界面
//界面是默认隐藏的所以要调用setVisible();
this.setVisible(true); //flase为隐藏 true为展示
}
}
包下的APP类游戏启动入口
import ui.gameJFrame;
import ui.loginJFrame;
import ui.registerJFrame;
//程序的启动入口
public class APP {
public static void main(String[] args) {
//创建主界面
new gameJFrame();
//创建登录界面
new loginJFrame();
//创建注册界面
new registerJFrame();
}
}
这里那么我们第一步就已经完成了 将界面和启动都创建好了
下一步则是将给界面设置和菜单设置
二、界面设置和菜单设置
将三个页面进行 设置标题、置顶、居中、和关闭的设置
//设置标题
this.setTitle("拼图游戏 v1.0");
//设置页面置顶
this.setAlwaysOnTop(true); //置顶在最上方 会盖住其他的软件
//设置界面居中
this.setLocationRelativeTo(null);
//游戏的关闭
this.setDefaultCloseOperation(3); //setDefaultCloseOperation()中的第三种模式
添加菜单
如图:
- JMenuBer为界面菜单的大类 JMenuBer中的每个选项为一个JMenu类
- 再往下JMenu的下拉菜单中有独立的JMenltem的选项对象
在gameJFrame类中添加菜单
//初始化菜单 创建整个菜单对象
JMenuBar JMenuBar0 = new JMenuBar();
//创建菜单中的选项对象
JMenu fJMenu01 = new JMenu("功能");
JMenu fJMenu02 = new JMenu("关于");
//创建选项下的条目对象
JMenuItem JMenuItem01 = new JMenuItem("重新游戏");
JMenuItem JMenuItem02 = new JMenuItem("重新登录");
JMenuItem JMenuItem03 = new JMenuItem("关闭游戏");
JMenuItem JMenuItem04 = new JMenuItem("加入讨论");
//将选项下条目添加到选项当中
fJMenu01.add(JMenuItem01);
fJMenu01.add(JMenuItem02);
fJMenu01.add(JMenuItem03);
fJMenu02.add(JMenuItem04);
//将菜单里的两个选项添加到菜单当中
JMenuBar0.add(fJMenu01);
JMenuBar0.add(fJMenu02);
//给整个界面添加菜单
this.setJMenuBar(JMenuBar0);
运行效果
三、给游戏界面添加图片
如图:
- 每一张图片就为一个Imagelcon对象
- 再将其放入JLabel中
图片素材:
java练习拼图游戏的源码及素材-Java文档类资源-CSDN文库
下载后解压将文件夹复制到IDEA的该项目模块中即可
给游戏界面添加图片
//创建Imagelcon对象
ImageIcon an1_01 = new ImageIcon("C:\\Users\\10076\\IdeaProjects\\untitled\\拼图游戏\\image\\animal\\animal1\\1.jpg");//图片路径
//创建JLabe对象(管理容器)
JLabel jLabel = new JLabel(an1_01);
//将JLabe添加到界面中
this.add(jLabel);
效果:
取消默认的居中放置
在gameJFrame类的构造器中写如下方法:
this.setLayout(null);
指定添加全部图片的位置
如图:
- 在界面中都有一个坐标 以右下角方向为准
- 左下角为坐标原点
因为在该拼图游戏中 图片的宽高为105像素 所以左上角为原点依次计算安排图片位置
调用JLable中的setBounds()方法来调整位置
int number = 1;
//用循环将图片加入主界面
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
//创建JLabe对象(管理容器)
JLabel jLabel = new JLabel(new ImageIcon("C:\\Users\\10076\\IdeaProjects\\untitled\\拼图游戏\\image\\animal\\animal1\\"+number+".jpg"));
//指定位置
jLabel.setBounds(105 * j, 105*i, 105, 105);
//将JLabe添加到界面中
//获取隐藏容器
this.getContentPane().add(jLabel);
number++;
}
因为素材图片每张的名称是从1到15的数字 所以在外定义一个number的变量 循环自增即可将全部图片加入
效果:
四、打乱图片
每张图片都是用一个数字表示
所以完成打乱图片的思路就是 利用数组存放相应数组 然后在容器中随机打乱顺序
在gameJFrame类中定义一个二维数组
int[][] data = new int[4][4];
打乱图片的初始化方法
//打乱图片
private void Datas(){
//定义一个数组
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//打乱数组中的顺序
Random r = new Random();
for (int i = 0; i < tempArr.length; i++) {
//获得随机索引
int rIndex = r.nextInt(tempArr.length);
//遍历数据交换
int temp = tempArr[i];
tempArr[i] =tempArr[rIndex];
tempArr[rIndex] = temp;
}
//将打乱的数据添加到二维数组
int index = 0;
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
data[i][j] = tempArr[index];
index++;
}
}
添加图片方法
//添加图片方法
private void InImage(){
//按二维数组中管理图片方式添加数据
//用循环将图片加入主界面
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
//获取要加载图片的序号
int num = data[i][j];
//创建JLabe对象(管理容器)
JLabel jLabel = new JLabel(new ImageIcon("C:\\Users\\10076\\IdeaProjects\\untitled\\拼图游戏\\image\\animal\\animal1\\"+num+".jpg"));
//指定位置
jLabel.setBounds(105 * j, 105*i, 105, 105);
//将JLabe添加到界面中
//获取隐藏容器
this.getContentPane().add(jLabel);
}
}
}
效果:
五、美化界面
需求如图:
- 将图片居中
- 给图片添加边框
图片居中
在指定位置中 计算出合适美观的偏移距离然后加在图片的位置中
//创建JLabe对象(管理容器)
JLabel jLabel = new JLabel(new ImageIcon("C:\\Users\\10076\\IdeaProjects\\untitled\\拼图游戏\\image\\animal\\animal1\\"+num+".jpg"));
//指定位置
jLabel.setBounds(105 * j+83, 105*i+115, 105, 105);
//将JLabe添加到界面中
//获取隐藏容器
this.getContentPane().add(jLabel);
效果:
添加背景图片
如图:在素材文件夹中有一个名为background的图片 为背景图片
//添加背景图片
//括号中传递背景图片的路径
//创建一个背景图片的管理容器
JLabel background = new JLabel(new ImageIcon("C:\\Users\\10076\\IdeaProjects\\untitled\\拼图游戏\\image\\background.png"));
//设置位置和宽高
background.setBounds(41,19,508,560);
//把背景图片添加到界面中
this.getContentPane().add(background);
细节:在这里 代码执行先加载的图片在上层 后加载的图片低层 所以要将背景代码写在最后
给每个小图片添加边框
选用setBorder方法 给图片添加边框 使用BevelBorder对象为斜面边框 0是凹下 1 是突起
//给图片添加边框
jLabel.setBorder(new BevelBorder(1)); //选用setBorder方法 给图片添加边框 使用BevelBorder对象为斜面边框 0是凹下 1 是突起
美化后的效果:
事件 移动图片
事件就是可以被组件识别的操作
- 事件源:如 按钮、图片、窗体
- 事件:某些操作
- 监听绑定:当事件源上发生了某个事件,则执行某段代码
六、上下左右移动
给整个游戏界面添加键盘监听事件
给gameJFram类实现KeyListener接口
public class gameJFrame extends JFrame implements KeyListener
然后重写里面的构造方法
在初始界面方法中给整个界面添加键盘监听事件
//给整个界面添加键盘监听事件
this.addKeyListener(this);
先定义存放坐标的变量
//定义存放坐标的变量
int x = 0;
int y = 0;
再进行判断添加到数组中
//将打乱的数据添加到二维数组
for (int i = 0; i < tempArr.length; i++) {
if (tempArr[i] == 0) {
x = i / 4;
y = i % 4;
}else {
data[i / 4][i % 4] = tempArr[i];
}
}
对上下左右进行判断
@Override
public void keyReleased(KeyEvent keyEvent) {
//对上下左右进行判断
//键盘对应的code码 左:37 上:38 右:39 下:40
int code = keyEvent.getKeyCode();
//对上下左右进行判断
if (code == 37){
System.out.println("向左移动");
}else if (code == 38){
System.out.println("向上移动");
}else if (code == 39){
System.out.println("向右移动");
}else if (code == 40){
System.out.println("向下移动");
}
}
如图:按下对应键盘上的方向键 会有对应提示
向上移动则是将空白方块下的图片向上移动
如图每个图片位置都有二维数组的索引
然后对向下的判断进行修改
@Override
public void keyReleased(KeyEvent keyEvent) {
//对上下左右进行判断
//键盘对应的code码 左:37 上:38 右:39 下:40
int code = keyEvent.getKeyCode();
//对上下左右进行判断
if (code == 37) {
System.out.println("向左移动");
//对边界进行判断
if (y == 3){
return;
}
data[x][y] = data[x][y + 1];
data[x][y + 1] = 0;
y++;
InImage();
} else if (code == 38) {
System.out.println("向上移动");
//对边界进行判断
if (x == 3){
//表示空白方块已经在最下方了 不能移动
return;
}
//逻辑:将空白方块下的数字往上移动
//x,y 就表示空白方块
//x+1,y不变 就表示空白方块下边方块的数字
//把空白方块下的数字赋值给上面的方块 下面的方块要变成0
data[x][y] = data[x + 1][y];
data[x + 1][y] = 0;
x++;
//调用方法 按照最新的数字加载图片
InImage();
} else if (code == 39) {
System.out.println("向右移动");
//对边界进行判断
if (y == 0){
return;
}
data[x][y] = data[x][y - 1];
data[x][y - 1] = 0;
y--;
InImage();
} else if (code == 40) {
System.out.println("向下移动");
//对边界进行判断
if (x == 0){
return;
}
data[x][y] = data[x - 1][y];
data[x - 1][y] = 0;
x--;
InImage();
}
}
再到 InImage()方法中
- 清空原有图片
//清空原本已经出现的所有图片
this.getContentPane().removeAll();
- 刷新一下界面
//刷新一下界面
this.getContentPane().repaint();
七、查看完整图片
给整个窗体绑定键盘监听事件
当按下R键时不松 将显示完整图片
//按下松时会调用这个方法
@Override
public void keyPressed(KeyEvent keyEvent) {
int code = keyEvent.getKeyCode();
//R键对应的code码为82
if (code == 82) {
//把界面所有的图片全部删除
this.getContentPane().removeAll();
//加载第一张完整的图片
JLabel all = new JLabel(new ImageIcon("拼图游戏\\image\\animal\\animal1\\all.jpg"));
//设置位置和宽高
all.setBounds(83, 134, 420, 420);
//把图片加载到界面中
this.getContentPane().add(all);
//加载背景图片
//括号中传递背景图片的路径
//创建一个背景图片的管理容器
JLabel background = new JLabel(new ImageIcon("拼图游戏\\image\\background.png"));
//设置位置和宽高
background.setBounds(41, 19, 508, 560);
//把背景图片添加到界面中
this.getContentPane().add(background);
//刷新界面
this.getContentPane().repaint();
}
}
在到 keyReleased方法中接着判断
else if(code == 82){
//重新加载图片
InImage();
重新改进一下路径 避免游戏时切换图片时查看完整图片会出问题
//定义当前展示图片的路径
String path = "拼图游戏\\image\\animal\\animal1\\";
//创建JLabe对象(管理容器)
JLabel jLabel = new JLabel(new ImageIcon( path+num + ".jpg"));
八、作弊码
安排一个快捷键 Z 按下即可复原拼图 一键通关
- 在到 keyReleased方法中接着判断
else if (code == 90) { //Z的code码为90
//将二维数组复原
data = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16},
};
//重新加载图片
InImage();
}
效果:
九、判断胜利
判断二维数组中的数据是否按照正确的顺序排列
//定义一个存放正确顺序的二维数组
int[][] win = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16},
};
//判断data中的数据是否和win数组中相同
public boolean victory() {
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;
}
在InImage()方法中
//调用判断胜利的方法 再对结果进行一个判断
if (victory()) {
//显示胜利的图标
JLabel winJLabel = new JLabel(new ImageIcon("拼图游戏\\image\\win.png"));
//设置位置
winJLabel.setBounds(203,283,197,73);
this.getContentPane().add(winJLabel);
}
在 keyReleased方法中进行判断
//判断游戏是否胜利如果胜利 该方法直接结束(不能再执行下面的移动代码了)
if (victory()){
return;
}
效果:
十、计步功能
//定义一个计步变量
int step = 0;
在InImage方法中创建一个 JLabel对象
//为步数显示创建一个对象
JLabel stepCount =new JLabel("步数:"+step);
//设置位置和宽高
stepCount.setBounds(50,30,100,20);
this.getContentPane().add(stepCount);
在 keyReleased方法中 上下左右每个键判断快结束时 让计步器自增一次
//每移动一次 计数器就自增一次
step++;
效果:
十一、重新游戏、关闭游戏、加入讨论 的菜单实现
给gameJFrame类再实现一个ActionListener接口 并重写里面的方法
public class gameJFrame extends JFrame implements KeyListener, ActionListener {
在初始化菜单Menu方法中 给菜单条目绑定事件
//创建选项下的条目对象
JMenuItem JMenuItem01 = new JMenuItem("重新游戏");
JMenuItem JMenuItem02 = new JMenuItem("重新登录");
JMenuItem JMenuItem03 = new JMenuItem("关闭游戏");
JMenuItem JMenuItem04 = new JMenuItem("加入讨论");
//将选项下条目添加到选项当中
fJMenu01.add(JMenuItem01);
fJMenu01.add(JMenuItem02);
fJMenu01.add(JMenuItem03);
fJMenu02.add(JMenuItem04);
//给条目绑定事件
JMenuItem01.addActionListener(this);
JMenuItem02.addActionListener(this);
JMenuItem03.addActionListener(this);
JMenuItem04.addActionListener(this);
在重写的 actionPerformed方法中做一个点击触发判断
@Override
public void actionPerformed(ActionEvent actionEvent) {
//获取当前被点击的条目对象
Object obj = actionEvent.getSource();
//判断当前点击的是谁
if (obj == JMenuItem01){
System.out.println("重新游戏");
}else if (obj == JMenuItem02){
System.out.println("重新登录");
}else if (obj == JMenuItem03){
System.out.println("关闭游戏");
}else if (obj == JMenuItem04){
System.out.println("加入讨论");
}
}
重新游戏
在重写的 actionPerformed方法中的if判断中实现重新游戏功能
if (obj == JMenuItem01) {
System.out.println("重新游戏");
//逻辑:
//计步器清零
step = 0;
//再次打乱二维数组中的顺序
Datas(); //调用之前写好的打乱方法
//重新加载图片
InImage();
}
重新登录
else if (obj == JMenuItem02) {
System.out.println("重新登录");
//返回登录界面
//关闭当前游戏界面
this.setVisible(false);
//打开登录界面
new loginJFrame();
}
关闭游戏
else if (obj == JMenuItem03) {
System.out.println("关闭游戏");
//直接关闭虚拟机
System.exit(0);
}
加入讨论
点击出现弹窗
新建一个JDalog对象 在到JDalog对象弹窗 添加图片新建一个ImageIcon的对象
else if (obj == JMenuItem04) {
System.out.println("加入讨论");
//创建一个弹框对象
JDialog jdialog =new JDialog();
//创建一个管理图片的容器对象
JLabel jLab = new JLabel(new ImageIcon("拼图游戏\\image\\animal\\animal4\\all.jpg"));
//设置图片在弹框中的位置
jLab.setBounds(0,0,420,420);
//把图片添加到弹框中
jdialog.getContentPane().add(jLab);
//给弹框设置大小
jdialog.setSize(430,430);
//让弹框置顶
jdialog.setAlwaysOnTop(true);
//让弹框居中
jdialog.setLocationRelativeTo(null);
//弹框不关闭则无法操作下面的界面、
jdialog.setModal(true);
//显示弹窗
jdialog.setVisible(true);
}
其余素材和源码下载链接
java练习拼图游戏的源码及素材-Java文档类资源-CSDN文库