(以下内容全部来自上述课程)
1.美化界面
private void initImage() {
//路径分两种:
//1.绝对路径:从盘符开始写的路径 D:\\aaa\\bbb\\ccc.jpg
//2.相对路径:从当前项目开始写的路径 aaa\\bbb\\ccc.jpg
//添加图片的时候,就需要按照二维数组中管理的数据添加图片
//外循环----把内循环的代码重复执行4次
for (int i = 0; i < 4; i++) {
//内循环----表示在一行中放4个图片
for (int j = 0; j < 4; j++) {
//获取二维数组中每个索引对应的数字
int number = arr[i][j];
//创建一个图片ImageIcon对象 参数:图片的路径(没加图片,意思一下得了)
//这里的图片最好命名为数字
ImageIcon icon = new ImageIcon("image\\background\\"+number+".jpg");
//创建一个JLabel对象(管理容器)
JLabel jLabel = new JLabel(icon);
//设置图片的位置
jLabel.setBounds(105*j+83,105*i+134,105,105);
//给图片添加边框
jLabel.setBorder(new BevelBorder(1));
//把JLabel对象添加到界面中
this.getContentPane().add(jLabel);
//添加一次后number自增1,表示下一次加载后面一张图片
}
}
//细节:
//先加载的图片在上方,后加载的图片在下方
//添加背景图片
ImageIcon background = new ImageIcon("image\\background\\background.jpg");
JLabel backgroundJLabel = new JLabel(background);
backgroundJLabel.setBounds(40,40,508,560);
//把背景图片添加到界面中
this.getContentPane().add(backgroundJLabel);
}
2.上下移动
上移动:
向上移动实际上就是把空白方块下方的图片上移。
(新加代码,非完整)
public class GameJFrame extends javax.swing.JFrame implements KeyListener {
//记录空白方块的位置
int x = 0;
int y = 0;
private void initImage() {
//清空原本已经出现的图片
this.getContentPane().removeAll();
}
private void initJFrame() {
//给整个界面添加键盘监听
this.addKeyListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
//对应键盘上的上下左右键
//获取键盘上的键码
int keyCode = e.getKeyCode();
System.out.println(keyCode);
if (keyCode == 38) {
System.out.println("上");
if (x == 3) {
//已经到底了,什么都不做
return;
}
//逻辑:
//把空白方块下方的数字往上移动
//x,y 表示空白方块
//x+1,y 表示空白方块上的位置
//把x+1,y位置上的数字赋值给x,y位置
arr[x][y] = arr[x+1][y];
arr[x+1][y] = 0;
//空白方块的位置发生了改变
x++;
//重新初始化图片
initImage();
} else if (keyCode == 40) {
if (x == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("下");
arr[x][y] = arr[x-1][y];
arr[x-1][y] = 0;
//空白方块的位置发生了改变
x--;
//重新初始化图片
initImage();
} else if (keyCode == 37) {
if (y == 3) {
//已经到底了,什么都不做
return;
}
System.out.println("左");
arr[x][y] = arr[x][y+1];
arr[x][y+1] = 0;
//空白方块的位置发生了改变
y++;
//重新初始化图片
initImage();
} else if (keyCode == 39) {
if (y == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("右");
arr[x][y] = arr[x][y-1];
arr[x][y-1] = 0;
//空白方块的位置发生了改变
y--;
//重新初始化图片
initImage();
} else {
System.out.println("其他");
}
}
}
3.查看完整图片的功能
按住A不松开,显示完整图片
松开A显示随机打乱的图片
(新加代码,非完整)
//定义一个变量,记录当前展示图片的路径
String path = "";
private void initImage() {
//清空原本已经出现的图片
this.getContentPane().removeAll();
//..........
//刷新界面
this.getContentPane().repaint();
}
//监听上一步添加过了,直接用,修改方法即可
//按下不松,一直触发
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == 65) {
//把界面中的所有图片全部删除
this.getContentPane().removeAll();
//加载第一张完整的图片
JLabel allJLabel = new JLabel(new ImageIcon(path+"all.jpg"));
//设置图片的位置
allJLabel.setBounds(83,134,420,420);
//把图片添加到界面中
this.getContentPane().add(allJLabel);
//加载背景图片
ImageIcon background = new ImageIcon("image\\background\\background.jpg");
JLabel backgroundJLabel = new JLabel(background);
backgroundJLabel.setBounds(40,40,508,560);
//把背景图片添加到界面中
this.getContentPane().add(backgroundJLabel);
//刷新界面
this.getContentPane().repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
//...........
} else if( keyCode == 65){
initImage();
}
}
}
4.作弊码
按一下W,直接胜利
keyReleased方法体中添加:
(新加代码,非完整)
else if (keyCode == 87) {
arr = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initImage();
5.判断胜利
其实就是判断二维数组中的数字是否按照顺序进行排列
如果按照顺序进行排列的,那么显示胜利的图片
实现步骤:
- 定义一个正确的二维数组win
- 在加载图片之前,先判断一下二维数组中的数字跟win数组中是否相同
- 如果相同展示正确图标
- 如果不同则不展示正确图标
(新加代码,非完整)
//定义一个二维数组,存储正确的数据
int[][] win = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};
private void initImage() {
//....
//判断游戏是否结束
if (isWin()) {
//显示胜利的图片
ImageIcon winIcon = new ImageIcon("image\\win.jpg");
JLabel winJLabel = new JLabel(winIcon);
winJLabel.setBounds(203,283,197,73);
this.getContentPane().add(winJLabel);
}
//........
}
public void keyReleased(KeyEvent e) {
//判断游戏是否胜利,如果胜利,此方法直接结束
if (isWin()) {
//1.返回结果
//2.结束方法
return;
//........
}
}
//判断游戏是否胜利
public boolean isWin(){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (arr[i][j] != win[i][j]){
return false;
}
}
}
return true;
}
6.计步功能
//定义变量,记录步数
int step = 0;
private void initImage() {
//........
JLabel stepCount = new JLabel("步数:"+step);
stepCount.setBounds(50,30,100,20);
this.getContentPane().add(stepCount);
//........
}
// keyReleased 截止到现在的完整代码
@Override
public void keyReleased(KeyEvent e) {
//判断游戏是否胜利,如果胜利,此方法直接结束
if (isWin()) {
//1.返回结果
//2.结束方法
return;
}
//对应键盘上的上下左右键
//获取键盘上的键码
int keyCode = e.getKeyCode();
System.out.println(keyCode);
if (keyCode == 38) {
System.out.println("上");
if (x == 3) {
//已经到底了,什么都不做
return;
}
//逻辑:
//把空白方块下方的数字往上移动
//x,y 表示空白方块
//x+1,y 表示空白方块上的位置
//把x+1,y位置上的数字赋值给x,y位置
arr[x][y] = arr[x+1][y];
arr[x+1][y] = 0;
//空白方块的位置发生了改变
x++;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 40) {
if (x == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("下");
arr[x][y] = arr[x-1][y];
arr[x-1][y] = 0;
//空白方块的位置发生了改变
x--;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 37) {
if (y == 3) {
//已经到底了,什么都不做
return;
}
System.out.println("左");
arr[x][y] = arr[x][y+1];
arr[x][y+1] = 0;
//空白方块的位置发生了改变
y++;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 39) {
if (y == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("右");
arr[x][y] = arr[x][y-1];
arr[x][y-1] = 0;
//空白方块的位置发生了改变
y--;
step++;
//重新初始化图片
initImage();
} else if( keyCode == 65){
initImage();
} else if (keyCode == 87) {
arr = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initImage();
}
}
7.菜单功能
1.重新开始
- 给重新游戏绑定点击事件---------->ActionListener
- 重新打乱二维数组中的数字
- 加载图片
- 计步器清零
2.关闭游戏
- 给关闭游戏绑定事件
- 结束虚拟机,关闭所有
3.关于我们
4.代码
(新加代码,非完整)
public class GameJFrame extends javax.swing.JFrame implements KeyListener , ActionListener {
//把条目添加到选项中 ----- 移到成员位置
functionJMenu.add(replayJMenuItem);
functionJMenu.add(reLoginJMenuItem);
functionJMenu.add(closeJMenuItem);
aboutJMenu.add(accountItem);
}
private void initJMenuBar() {
//.........
//给条目绑定事件
replayJMenuItem.addActionListener(this);
reLoginJMenuItem.addActionListener(this);
closeJMenuItem.addActionListener(this);
accountItem.addActionListener(this);
}
//initData 截止到现在的完整代码
private void initData() {
//1.定义一个一维数组
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//2.随机打乱一维数组中的数据
for (int i = 0; i < tempArr.length; i++) {
//获取随机索引
int randomIndex = (int)(Math.random()*tempArr.length);
//拿着随机索引对应的值和i索引对应的值进行交换
int temp = tempArr[i];
tempArr[i] = tempArr[randomIndex];
tempArr[randomIndex] = temp;
}
//3.遍历一维数组
for (int i = 0; i < tempArr.length; i++) {
if (tempArr[i] == 0) {
x = i / 4;
y = i % 4;
}
arr[i / 4][i % 4] = tempArr[i];
}
System.out.println();
}
@Override
public void actionPerformed(ActionEvent e) {
//获取被点击的条目对象
Object obj = e.getSource();
if (obj == replayJMenuItem) {
System.out.println("重新游戏");
//步数清零
step = 0;
//重新打乱数据
initData();
//重新初始化图片
initImage();
} else if (obj == reLoginJMenuItem) {
System.out.println("重新登录");
//关闭当前登录的界面
this.setVisible(false);
//打开登录界面
new LoginJFrame();
} else if (obj == closeJMenuItem) {
System.out.println("关闭游戏");
System.exit(0);
} else if (obj == accountItem) {
System.out.println("公众号");
//创建一个弹窗对象
JDialog jDialog = new JDialog();
//创建一个管理图片的容器
JLabel jLabel = new JLabel(new ImageIcon("image\\account.jpg"));
//设置位置和宽高
jLabel.setBounds(0,0,258,258);
//把图片添加到弹窗中
jDialog.getContentPane().add(jLabel);
//设置弹窗的宽高
jDialog.setSize(280,316);
//设置弹窗置顶
jDialog.setAlwaysOnTop(true);
//设置弹窗居中
jDialog.setLocationRelativeTo(null);
//弹框不关闭无法操作下面的界面
jDialog.setModal(true);
//让弹窗显示出来
jDialog.setVisible(true);
}
}
8.游戏打包exe(概括)
- 一定要包含图形化界面
- 代码要打包起来
- 游戏用到的图片也要打包起来
- JDK也要打包起来
步骤:
- 把所有代码打包成一个压缩包,jar后缀的压缩包
- 把jar包转换成exe安装包
- 把第二步的exe,图片,JDK整合在一起,变成最终的exe安装包
9.所有完整代码
1.GameJFrame
package com.woziji.ui;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
public class GameJFrame extends javax.swing.JFrame implements KeyListener , ActionListener {
//JFrame 界面,窗体
//子类呢? 也表示界面,窗体
//规定:GameJFrame 表示游戏的主界面
//以后和游戏相关的所有逻辑都写在这个类中
//用来管理数据
int[][] arr = new int[4][4];
//记录空白方块的位置
int x = 0;
int y = 0;
//定义一个变量,记录当前展示图片的路径
String path = "";
//定义一个二维数组,存储正确的数据
int[][] win = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};
//定义变量,记录步数
int step = 0;
//创建选项下面的条目对象
JMenuItem replayJMenuItem = new JMenuItem("重新游戏");
JMenuItem reLoginJMenuItem = new JMenuItem("重新登录");
JMenuItem closeJMenuItem = new JMenuItem("关闭游戏");
JMenuItem accountItem = new JMenuItem("公众号");
public GameJFrame() {
//初始化界面
initJFrame();
//初始化菜单
initJMenuBar();
//初始化数据(打乱)
initData();
//初始化图片
initImage();
//让界面显示出来,建议写在最后
this.setVisible(true);
}
private void initData() {
//1.定义一个一维数组
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//2.随机打乱一维数组中的数据
for (int i = 0; i < tempArr.length; i++) {
//获取随机索引
int randomIndex = (int)(Math.random()*tempArr.length);
//拿着随机索引对应的值和i索引对应的值进行交换
int temp = tempArr[i];
tempArr[i] = tempArr[randomIndex];
tempArr[randomIndex] = temp;
}
//3.遍历一维数组
for (int i = 0; i < tempArr.length; i++) {
if (tempArr[i] == 0) {
x = i / 4;
y = i % 4;
}
arr[i / 4][i % 4] = tempArr[i];
}
System.out.println();
}
private void initImage() {
//清空原本已经出现的图片
this.getContentPane().removeAll();
//判断游戏是否结束
if (isWin()) {
//显示胜利的图片
ImageIcon winIcon = new ImageIcon("image\\win.jpg");
JLabel winJLabel = new JLabel(winIcon);
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);
//路径分两种:
//1.绝对路径:从盘符开始写的路径 D:\\aaa\\bbb\\ccc.jpg
//2.相对路径:从当前项目开始写的路径 aaa\\bbb\\ccc.jpg
//添加图片的时候,就需要按照二维数组中管理的数据添加图片
//外循环----把内循环的代码重复执行4次
for (int i = 0; i < 4; i++) {
//内循环----表示在一行中放4个图片
for (int j = 0; j < 4; j++) {
//获取二维数组中每个索引对应的数字
int number = arr[i][j];
//创建一个图片ImageIcon对象 参数:图片的路径(没加图片,意思一下得了)
//这里的图片最好命名为数字
ImageIcon icon = new ImageIcon("image\\background\\"+number+".jpg");
//创建一个JLabel对象(管理容器)
JLabel jLabel = new JLabel(icon);
//设置图片的位置
jLabel.setBounds(105*j+83,105*i+134,105,105);
//给图片添加边框
jLabel.setBorder(new BevelBorder(1));
//把JLabel对象添加到界面中
this.getContentPane().add(jLabel);
//添加一次后number自增1,表示下一次加载后面一张图片
}
}
//细节:
//先加载的图片在上方,后加载的图片在下方
//添加背景图片
ImageIcon background = new ImageIcon("image\\background\\background.jpg");
JLabel backgroundJLabel = new JLabel(background);
backgroundJLabel.setBounds(40,40,508,560);
//把背景图片添加到界面中
this.getContentPane().add(backgroundJLabel);
//刷新界面
this.getContentPane().repaint();
}
private void initJMenuBar() {
//创建整个的菜单对象
JMenuBar JMenuBar = new JMenuBar();
//创建菜单上面的两个选项的对象 (功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
//把条目添加到选项中
functionJMenu.add(replayJMenuItem);
functionJMenu.add(reLoginJMenuItem);
functionJMenu.add(closeJMenuItem);
aboutJMenu.add(accountItem);
//把选项添加到菜单中
JMenuBar.add(functionJMenu);
JMenuBar.add(aboutJMenu);
//把菜单设置到界面中
this.setJMenuBar(JMenuBar);
//给条目绑定事件
replayJMenuItem.addActionListener(this);
reLoginJMenuItem.addActionListener(this);
closeJMenuItem.addActionListener(this);
accountItem.addActionListener(this);
}
private void initJFrame() {
//设置界面的宽高
this.setSize(603,680);
//设置界面的标题
this.setTitle("拼图单机版 v1.0");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置界面的关闭方式
this.setDefaultCloseOperation(3);
//取消默认的居中放置,只有取消了才可以设置坐标
this.setLayout(null);
//给整个界面添加键盘监听
this.addKeyListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
}
//按下不松,一直触发
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == 65) {
//把界面中的所有图片全部删除
this.getContentPane().removeAll();
//加载第一张完整的图片
JLabel allJLabel = new JLabel(new ImageIcon(path+"all.jpg"));
//设置图片的位置
allJLabel.setBounds(83,134,420,420);
//把图片添加到界面中
this.getContentPane().add(allJLabel);
//加载背景图片
ImageIcon background = new ImageIcon("image\\background\\background.jpg");
JLabel backgroundJLabel = new JLabel(background);
backgroundJLabel.setBounds(40,40,508,560);
//把背景图片添加到界面中
this.getContentPane().add(backgroundJLabel);
//刷新界面
this.getContentPane().repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
//判断游戏是否胜利,如果胜利,此方法直接结束
if (isWin()) {
//1.返回结果
//2.结束方法
return;
}
//对应键盘上的上下左右键
//获取键盘上的键码
int keyCode = e.getKeyCode();
System.out.println(keyCode);
if (keyCode == 38) {
System.out.println("上");
if (x == 3) {
//已经到底了,什么都不做
return;
}
//逻辑:
//把空白方块下方的数字往上移动
//x,y 表示空白方块
//x+1,y 表示空白方块上的位置
//把x+1,y位置上的数字赋值给x,y位置
arr[x][y] = arr[x+1][y];
arr[x+1][y] = 0;
//空白方块的位置发生了改变
x++;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 40) {
if (x == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("下");
arr[x][y] = arr[x-1][y];
arr[x-1][y] = 0;
//空白方块的位置发生了改变
x--;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 37) {
if (y == 3) {
//已经到底了,什么都不做
return;
}
System.out.println("左");
arr[x][y] = arr[x][y+1];
arr[x][y+1] = 0;
//空白方块的位置发生了改变
y++;
step++;
//重新初始化图片
initImage();
} else if (keyCode == 39) {
if (y == 0) {
//已经到底了,什么都不做
return;
}
System.out.println("右");
arr[x][y] = arr[x][y-1];
arr[x][y-1] = 0;
//空白方块的位置发生了改变
y--;
step++;
//重新初始化图片
initImage();
} else if( keyCode == 65){
initImage();
} else if (keyCode == 87) {
arr = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initImage();
}
}
//判断游戏是否胜利
public boolean isWin(){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (arr[i][j] != win[i][j]){
return false;
}
}
}
return true;
}
@Override
public void actionPerformed(ActionEvent e) {
//获取被点击的条目对象
Object obj = e.getSource();
if (obj == replayJMenuItem) {
System.out.println("重新游戏");
//步数清零
step = 0;
//重新打乱数据
initData();
//重新初始化图片
initImage();
} else if (obj == reLoginJMenuItem) {
System.out.println("重新登录");
//关闭当前登录的界面
this.setVisible(false);
//打开登录界面
new LoginJFrame();
} else if (obj == closeJMenuItem) {
System.out.println("关闭游戏");
System.exit(0);
} else if (obj == accountItem) {
System.out.println("公众号");
//创建一个弹窗对象
JDialog jDialog = new JDialog();
//创建一个管理图片的容器
JLabel jLabel = new JLabel(new ImageIcon("image\\account.jpg"));
//设置位置和宽高
jLabel.setBounds(0,0,258,258);
//把图片添加到弹窗中
jDialog.getContentPane().add(jLabel);
//设置弹窗的宽高
jDialog.setSize(280,316);
//设置弹窗置顶
jDialog.setAlwaysOnTop(true);
//设置弹窗居中
jDialog.setLocationRelativeTo(null);
//弹框不关闭无法操作下面的界面
jDialog.setModal(true);
//让弹窗显示出来
jDialog.setVisible(true);
}
}
}
2.LoginJFrame
package com.woziji.ui;
import javax.swing.*;
public class LoginJFrame extends javax.swing.JFrame{
//登录界面
//以后和登录相关的所有逻辑都写在这个类中
public LoginJFrame(){
//在创建登陆界面的时候,同时给这个界面去设置一些信息
//比如:宽高,直接展示出来
this.setSize(488,430);
this.setVisible(true);
//设置界面的标题
this.setTitle("拼图 登录");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置界面的关闭方式
this.setDefaultCloseOperation(3);
}
}
3.RegisterJFrame
package com.woziji.ui;
public class RegisterJFrame extends javax.swing.JFrame{
//注册界面
//以后和注册相关的所有逻辑都写在这个类中
public RegisterJFrame(){
this.setSize(488,500);
this.setVisible(true);
//设置界面的标题
this.setTitle("拼图 注册");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中
this.setLocationRelativeTo(null);
//设置界面的关闭方式
this.setDefaultCloseOperation(3);
}
}
4.主入口
import com.woziji.ui.GameJFrame;
import com.woziji.ui.LoginJFrame;
import com.woziji.ui.RegisterJFrame;
public class App {
public static void main(String[] args) {
//表示程序的入口
//如果我们想开启一个界面,就创建谁的对象
//new LoginJFrame();
//new RegisterJFrame();
new GameJFrame();
}
}