1.通过可视化界面完成项目
2.添加事件监听进行游戏操作
通过鼠标单击菜单实现重新游戏,重新登录,退出游戏和弹出公众号二维码弹窗
通过上下左右键操控拼图移动
通过长按W键显示完整拼图样式
通过按键A实现一键通关
3.创建可视化计数器记录拼图移动步数
4.胜利后显示胜利图标
详细要求请见注释要求
核心思路
定义数组,一个数字对应一快拼图,打乱数组,相当于打乱拼图
0代表空白拼图,定义x,y记录0的坐标,例如上述x=2,y=1
App类(代码主入口)
public class App {
public static void main(String[] args) {
//创建游戏界面
new GameJFrame();
}
}
游戏界面类
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
//游戏界面类继承界面类,实现键盘监听和动作监听
public class GameJFrame extends JFrame implements KeyListener, ActionListener {
//多个方法需要用到的变量,记录在成员变量的位置
//定义二维数组记录打乱后的0~15,每一个数字对应一张拼图
int data[][] = new int[4][4];
//定义胜利时的数据数组
int[][] winArr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
//定义坐标记录0的位置
int x = 0;
int y = 0;
//定义计数器记录移动步数
int stepCount = 0;
//创建菜单选项里下面的条目
JMenuItem restartItem = new JMenuItem("重新开始");
JMenuItem reLoginItem = new JMenuItem("重新登录");
JMenuItem exitItem = new JMenuItem("退出游戏");
JMenuItem AccountItem = new JMenuItem("公众号");
//定义图片路径,方便后面修改
String path = "PuzzleGame\\image\\animal\\animal1\\";
//空参构造初始化游戏
public GameJFrame() {
//调用方法初始化界面
initFrame();
//给界面添加事件监听,键盘监听KeyListener
this.addKeyListener(this);
//调用方法添加菜单
initMenu();
//给菜单里的条目添加事件监听,动作监听ActionListener
restartItem.addActionListener(this);
reLoginItem.addActionListener(this);
exitItem.addActionListener(this);
AccountItem.addActionListener(this);
//调用方法初始化数据
initData();
//调用方法根据初始化后的数据加载图片
loadImages();
//设置界面可视,建议放在最后
this.setVisible(true);
}
//定义方法判断游戏是否胜利
private boolean victoty() {
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] != winArr[i][j]) {
//data中的数据有一个与胜利数组中的数据不同,就说明没有胜利
return false;
}
}
}
return true;
}
//定义方法根据初始化后的数据加载图片
private void loadImages() {
//清空所有图片
this.getContentPane().removeAll();
//如果胜利,加载胜利图标
if (victoty()) {
JLabel vicJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\win.png"));
vicJLabel.setBounds(203, 283, 197, 73);
this.getContentPane().add(vicJLabel);
}
//加载计数器
JLabel countJLabel = new JLabel("步数:" + stepCount);
countJLabel.setBounds(50, 30, 100, 20);
this.getContentPane().add(countJLabel);
//利用循环加载拼图图片
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
//获得data数组里的数据
int number = data[i][j];
//根据数据创建图片对象
ImageIcon icon = new ImageIcon(path + number + ".jpg");
//创建管理容器,将图片交给管理容器
JLabel jLabel = new JLabel(icon);
//设置管理容器位置,大小
jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);
//设置边框
jLabel.setBorder(new BevelBorder(0));
//将管理容器添加到界面中
this.getContentPane().add(jLabel);
}
}
//添加背景图片
JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));
bgJLabel.setBounds(40, 40, 508, 560);
this.getContentPane().add(bgJLabel);
//刷新一下
this.getContentPane().repaint();
}
//定义方法初始化数据
private void initData() {
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 index = r.nextInt(tempArr.length);
int temp = tempArr[i];
tempArr[i] = tempArr[index];
tempArr[index] = temp;
}
//将打乱后的数据记录在二维数组data中
for (int i = 0; i < tempArr.length; i++) {
//如果是0,记录0的位置
if (tempArr[i] == 0) {
x = i / 4;
y = i % 4;
}
data[i / 4][i % 4] = tempArr[i];
}
}
//定义方法添加菜单
private void initMenu() {
//创建菜单
JMenuBar jMenuBar = new JMenuBar();
//创建菜单的选项
JMenu functionJmenu = new JMenu("功能");
JMenu aboutJmenu = new JMenu("关于我们");
//将条目添加到选项中
functionJmenu.add(restartItem);
functionJmenu.add(reLoginItem);
functionJmenu.add(exitItem);
aboutJmenu.add(AccountItem);
//将选项添加到菜单中
jMenuBar.add(functionJmenu);
jMenuBar.add(aboutJmenu);
//将菜单添加到界面中
this.setJMenuBar(jMenuBar);
}
//定义方法初始化界面
private void initFrame() {
//设置大小
this.setSize(603, 680);
//设置标题
this.setTitle("拼图游戏");
//设置居中
this.setLocationRelativeTo(null);
//设置置顶
this.setAlwaysOnTop(true);
//设置关闭模式
this.setDefaultCloseOperation(3);
//设置解除默认居中放置,只有解除了,才能根据xy轴的方式添加主件
this.setLayout(null);
}
//动作监听ActionListener,鼠标单击或按空格调用该方法
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == restartItem) {
//重新开始
//重新初始化数据
initData();
//计数器归0
stepCount = 0;
//重新根据初始化后的数据加载图片
loadImages();
} else if (source == reLoginItem) {
//重新登录
//关闭本类(游戏类)
this.setVisible(false);
//创建登录界面
//new LoginJFrame();
} else if (source == exitItem) {
//退出游戏
System.exit(0);
} else if (source == AccountItem) {
//显示公众号
//创建弹窗
JDialog accJDialog = new JDialog();
//加载弹窗中的图片
JLabel aboutJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\about.png"));
aboutJLabel.setBounds(0, 0, 258, 258);
//将图片添加到弹窗中
accJDialog.getContentPane().add(aboutJLabel);
//设置弹窗的大小
accJDialog.setSize(344, 344);
//设置弹窗置顶
accJDialog.setAlwaysOnTop(true);
//设置弹窗居中放置
accJDialog.setLocationRelativeTo(null);
//设置关闭后进行其他操作
accJDialog.setModal(true);
//设置弹窗可视
accJDialog.setVisible(true);
}
}
//键盘监听KeyListener
//该方法基本不使用
@Override
public void keyTyped(KeyEvent e) {
}
//长按键盘时调用该方法
@Override
public void keyPressed(KeyEvent e) {
//判断是否胜利
if (victoty()) {
//如果胜利,禁止进行显示全图操作,直接结束方法
return;
}
//长按w显示全图
int keyCode = e.getKeyCode();
if (keyCode == 87) {
//清空所有图片
this.getContentPane().removeAll();
//加载计数器
JLabel countJLabel = new JLabel("步数:" + stepCount);
countJLabel.setBounds(50, 30, 100, 20);
this.getContentPane().add(countJLabel);
//加载全图
JLabel picJLabel = new JLabel(new ImageIcon(path + "all.jpg"));
picJLabel.setBounds(83, 134, 420, 420);
this.getContentPane().add(picJLabel);
//添加背景图片
JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));
bgJLabel.setBounds(40, 40, 508, 560);
this.getContentPane().add(bgJLabel);
//刷新一下
this.getContentPane().repaint();
}
}
//按下并松开键盘时调用该方法
@Override
public void keyReleased(KeyEvent e) {
//判断是否胜利
if (victoty()) {
//如果胜利,禁止进行移动操作,直接结束方法
return;
}
int keyCode = e.getKeyCode();
if (keyCode == 37) {
//判断是否到了最左边
if (y == 0) {
//如果到了最左边,不能进行向左,直接结束方法
return;
}
//没到最左边,进行下面的操作
System.out.println("向左");
//更改data数组里的数据
data[x][y] = data[x][y - 1];
data[x][y - 1] = 0;
//更改0的坐标
y--;
//步数加1
stepCount++;
//按照此数据重新加载图片
loadImages();
} else if (keyCode == 38) {
//判断是否到了最上边
if (x == 0) {
//如果到了最上边,不能进行向上,直接结束方法
return;
}
//没到最上边,进行下面的操作
System.out.println("向上");
//更改data数组里的数据
data[x][y] = data[x - 1][y];
data[x - 1][y] = 0;
//更改0的坐标
x--;
//步数加1
stepCount++;
//按照此数据重新加载图片
loadImages();
} else if (keyCode == 39) {
//判断是否到了最右边
if (y == 3) {
//如果到了最右边,不能进行向右,直接结束方法
return;
}
//没到最右边,进行下面的操作
System.out.println("向右");
//更改data数组里的数据
data[x][y] = data[x][y + 1];
data[x][y + 1] = 0;
//更改0的坐标
y++;
//步数加1
stepCount++;
//按照此数据重新加载图片
loadImages();
} else if (keyCode == 40) {
//判断是否到了最下边
if (x == 3) {
//如果到了最下边,不能进行向下,直接结束方法
return;
}
//没到最下边,进行下面的操作
System.out.println("向下");
//更改data数组里的数据
data[x][y] = data[x + 1][y];
data[x + 1][y] = 0;
//更改0的坐标
x++;
//步数加1
stepCount++;
//按照此数据重新加载图片
loadImages();
} else if (keyCode == 87) {
//松开w恢复原状
loadImages();
} else if (keyCode == 65) {
//一键通过
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
data[i][j] = winArr[i][j];
}
}
loadImages();
}
}
}