用JAVA的JFrame,JButton等工具实现拼图小游戏,包括拼图功能,更换图片功能,重新开始功能等等。
首先创建一个名为GameJframe的类,通过setSize()方法以及setTitle()等方法来初始化一个JFrame窗口,并设置标题为“拼图单机版”,通过setAlwaysOnTop()方法设置窗口置顶,并通过setLocationRelativeTo()方法设置窗口居中,而为使玩家可以通过关闭游戏窗口而关闭整个进程,我们则需设置默认关闭模式,当setDefaultCloseOperation()中参数为3即可。
//设置窗口宽、高
this.setSize(603, 680);
//设置窗口标题
this.setTitle("拼图单机版");
//设置窗口置顶
this.setAlwaysOnTop(true);
//设置窗口置中
this.setLocationRelativeTo(null);
//设置窗口关闭模式
/*
setDefaultCloseOperation()里的参数为0时,窗口不可关闭
为1时,则为默认关闭模式
为2时,则需关闭所有窗口才可完全关闭虚拟机
为3时,则只需关闭一个窗口即可完全关闭虚拟机
*/
this.setDefaultCloseOperation(3);
为搭建菜单,需通过创建JMenuBar和JMenu对象实现,通过其中的add()方法将需要的菜单选项添加到窗口中即可。
//创建整个菜单对象
JMenuBar jmb = new JMenuBar();
//创建菜单下三个选项对象
JMenu functionjm = new JMenu("菜单");
JMenu aboutjm = new JMenu("关于我");
JMenu changeimage = new JMenu("更换图片");
拼图游戏自然要有图片以供我们拼接,为此我们需准备好相应的图片资源,并复制粘贴至项目所在的文件夹中,通过创建JLabel对象和ImageIcon对象来管理图片,通过其中的成员方法setBounds()来设置图片大小以及setBorder()方法来设置图片格式,方法中参数为0时表示让图片凸出来,参数为1则表示让图片凹进去,为美观,我们选择将参数设为1,然后通过getContentpane()方法来添加进去。
//创建一个JLabel管理容器
JLabel jl = new JLabel(new ImageIcon(path+temppath+temp+"\\"+count+".jpg"));
//设置图片位置以及大小
jl.setBounds(105*j+83,105*i+134,105,105);
//给图片设置边框
//参数为0时表示让图片凸出来
//参数为1时表示让图片凹进去
jl.setBorder(new BevelBorder(1));
this.getContentPane().add(jl);
在添加完图片后,为打乱图片,我们可以将图片分为16份,15份索引和一份空白图片,所以我们只需创建一个如下的4行4列的二维数组,将随机打乱后的位置索引存储进去,在添加图片时按照打乱后的索引进行添加即可。
11 | 1 | 15 | 4 |
3 | 10 | 5 | 9 |
8 | 2 | 6 | 7 |
0 | 12 | 14 | 13 |
//存储打乱后的索引
private int[][] data = new int[4][4];
int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//数组随机索引
int temp = 0;
Random r = new Random();
//打乱数组元素
for (int i = 0; i < arr.length; i++) {
int index = r.nextInt(arr.length);
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
//给二位数组添加打乱后的元素
for (int i = 0; i < arr.length; i++) {
//若当前元素为空白元素,则令x和y为当前元素的位置
if (arr[i] == 0){
x = i / 4;
y = i % 4;
}
data[i / 4][i % 4] = arr[i];
}
在我们玩游戏时,需要对图片进行操作,这时候就需要用到监听这个接口了,比如在编写图片移动功能时,我们就要对键盘进行监听,当我们按到w键或者上箭头时,空白格子下方的图片就会向上移动一格,所以我们要实现KeyListener接口,并重写keyRelease()方法即可。
if (code == 37 || code == 65){
System.out.println("向左移动");
//实现空白图片右方的图片向左移动
if (y == 3){
return;
}
data[x][y] = data[x][y+1];
data[x][y+1] = 0;
y++;
step++;
//调用方法按照最新的数字加载图片
initimage();
}
为美化图片,使玩家获得更好游戏体验,只需为图片添加一个背景即可。
//添加背景图片
JLabel jb = new JLabel(new ImageIcon("image\\background.png"));
jb.setBounds(40,40,508,560);
this.getContentPane().add(jb);
为了实现计步功能,只需定义一个成员变量来储存步数,当移动一次时,步数加一,当选择重新开始游戏或者更换图片时,步数清零即可。而菜单业务则与上文的移动功能类似,也需实现监听接口,当鼠标点击该功能按钮时,就要进行相应的操作。
Object obj = e.getSource();
if (obj == restartjmi){
System.out.println("重新游戏");
//计步器清零
step = 0;
//初始化数据
initdata();
//初始化图片
initimage();
}
else if(obj == closejmi){
System.out.println("关闭游戏");
//关闭虚拟机
System.exit(0);
}else if(obj == accountjmi){
System.out.println("名片");
JDialog jdi = new JDialog();
JLabel jb = new JLabel(new ImageIcon("image\\mingpian.jpg"));
//设置位置
jb.setBounds(0,0,300,299);
jdi.getContentPane().add(jb);
//设置弹框大小
jdi.setSize(344,344);
//设置弹框置顶
jdi.setAlwaysOnTop(true);
//设置弹框居中
jdi.setLocationRelativeTo(null);
//设置弹框不关闭无法继续
jdi.setModal(true);
//设置弹框可视化
jdi.setVisible(true);
}else if (obj == girl) {
System.out.println("更换美女图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\girl\\girl";
changei();
}else if (obj == animal) {
System.out.println("更换动物图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\animal\\animal";
changei();
}else if (obj == sport) {
System.out.println("更换运动图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\sport\\sport";
changei();
}
完整代码:
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 {
//存储打乱后的索引
private int[][] data = new int[4][4];
//创建选项下的条目对象
JMenuItem restartjmi = new JMenuItem("重新开始");
//JMenuItem relogjmi = new JMenuItem("重新登录");
JMenuItem closejmi = new JMenuItem("关闭游戏");
JMenuItem girl = new JMenuItem("美女");
JMenuItem animal = new JMenuItem("动物");
JMenuItem sport = new JMenuItem("运动");
JMenuItem accountjmi = new JMenuItem("名片");
//记录空白图片在二维数组中的位置
private int x = 0;
private int y = 0;
//定义路径
String path = "image";
String temppath = "\\girl\\girl";
int temp = 1;
//String path = "image";
//定义一个胜利数组
private int[][] win = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
//定义变量来统计步数
private int step = 0;
//判断data数组中的值是否跟win数组中的值完全相同
//相同则胜利,返回true。不同则继续,返回false
public boolean victory(){
//判断data数组元素与win数组元素是否全部相同
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if (data[i][j] != win[i][j]){
return false;
}
}
}
//遍历结束,全部相同返回true
return true;
}
public GameJFrame() {
//初始化窗口
initjf();
//初始化菜单
initjmbar();
//初始化数据
initdata();
//初始化图片
initimage();
//设置窗口可视化
this.setVisible(true);
}
private void initdata() {
int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//数组随机索引
int temp = 0;
Random r = new Random();
//打乱数组元素
for (int i = 0; i < arr.length; i++) {
int index = r.nextInt(arr.length);
temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
//给二维数组添加打乱后的索引
// int index = 0;
// for (int i = 0; i < 4; i++) {
// for (int j = 0; j < 4; j++) {
// data[i][j] = arr[index];
// index++;
// }
// }
//给二位数组添加打乱后的元素
for (int i = 0; i < arr.length; i++) {
//若当前元素为空白元素,则令x和y为当前元素的位置
if (arr[i] == 0){
x = i / 4;
y = i % 4;
}
data[i / 4][i % 4] = arr[i];
}
}
private void initimage(){
//删除所有图片
this.getContentPane().removeAll();
//调用victory方法判断是否胜利
if (victory()) {
JLabel win = new JLabel(new ImageIcon("image\\win.png"));
//JLabel win = new JLabel(new ImageIcon("image\\win.png"));
win.setBounds(203,283,197,73);
this.getContentPane().add(win);
}
JLabel jbstep = new JLabel("步数: "+step);
jbstep.setBounds(50,30,100,20);
this.getContentPane().add(jbstep);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
int count = data[i][j];
//创建一个JLabel管理容器
JLabel jl = new JLabel(new ImageIcon(path+temppath+temp+"\\"+count+".jpg"));
//设置图片位置以及大小
jl.setBounds(105*j+83,105*i+134,105,105);
//给图片设置边框
//参数为0时表示让图片凸出来
//参数为1时表示让图片凹进去
jl.setBorder(new BevelBorder(1));
this.getContentPane().add(jl);
}
}
//添加背景图片
JLabel jb = new JLabel(new ImageIcon("image\\background.png"));
jb.setBounds(40,40,508,560);
this.getContentPane().add(jb);
//刷新加载图片
this.getContentPane().repaint();
}
private void changei(){
Random r = new Random();
if ((path+temppath).equals("image\\girl\\girl")){
temp = r.nextInt(13)+1;
initimage();
}else if((path+temppath).equals("image\\animal\\animal")){
temp = r.nextInt(8)+1;
initimage();
}else if((path+temppath).equals("image\\sport\\sport")){
temp = r.nextInt(10)+1;
initimage();
}
}
private void initjmbar() {
//创建整个菜单对象
JMenuBar jmb = new JMenuBar();
//创建菜单下三个选项对象
JMenu functionjm = new JMenu("菜单");
JMenu aboutjm = new JMenu("关于我");
JMenu changeimage = new JMenu("更换图片");
//添加条目对象到选项对象中
functionjm.add(changeimage);
functionjm.add(restartjmi);
//functionjm.add(relogjmi);
functionjm.add(closejmi);
aboutjm.add(accountjmi);
changeimage.add(girl);
changeimage.add(animal);
changeimage.add(sport);
//给条目绑定事件
restartjmi.addActionListener(this);
//relogjmi.addActionListener(this);
closejmi.addActionListener(this);
accountjmi.addActionListener(this);
girl.addActionListener(this);
animal.addActionListener(this);
sport.addActionListener(this);
//将选项对象添加到菜单对象中
jmb.add(functionjm);
jmb.add(aboutjm);
//给整个界面设置菜单
this.setJMenuBar(jmb);
}
private void initjf(){
//设置窗口宽、高
this.setSize(603, 680);
//设置窗口标题
this.setTitle("拼图单机版");
//设置窗口置顶
this.setAlwaysOnTop(true);
//设置窗口置中
this.setLocationRelativeTo(null);
//设置窗口关闭模式
/*
setDefaultCloseOperation()里的参数为0时,窗口不可关闭
为1时,则为默认关闭模式
为2时,则需关闭所有窗口才可完全关闭虚拟机
为3时,则只需关闭一个窗口即可完全关闭虚拟机
*/
this.setDefaultCloseOperation(3);
//添加键盘监听指针
this.addKeyListener(this);
//只有取消居中,才可以将图片放到指定位置
this.setLayout(null);
}
@Override
public void keyTyped(KeyEvent e) {
}
//按下A键不松开时会调用此方法实现图片还原功能
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == 73){
//将界面中的图片全部删除
this.getContentPane().removeAll();
//加载一张完整图片
JLabel jb = new JLabel(new ImageIcon(path+temppath+temp+"\\"+"all.jpg"));
jb.setBounds(83,134,420,420);
this.getContentPane().add(jb);
//加载背景图片
JLabel jb1 = new JLabel(new ImageIcon("image\\background.png"));
jb1.setBounds(40,40,508,560);
this.getContentPane().add(jb1);
//刷新界面
this.getContentPane().repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
//判断游戏是否胜利,胜利则直接结束,不用执行下面的代码
if (victory()) {
return;
}
if (code == 37 || code == 65){
System.out.println("向左移动");
//实现空白图片右方的图片向左移动
if (y == 3){
return;
}
data[x][y] = data[x][y+1];
data[x][y+1] = 0;
y++;
step++;
//调用方法按照最新的数字加载图片
initimage();
}else if(code == 38 || code == 87){
System.out.println("向上移动");
//实现空白图片下方的图片向上移动
if (x == 3){
return;
}
data[x][y] = data[x+1][y];
data[x+1][y] = 0;
x++;
step++;
//调用方法按照最新的数字加载图片
initimage();
}else if(code == 39 || code == 68)
{
System.out.println("向右移动");
//实现空白图片左方的图片向右移动
if (y == 0){
return;
}
data[x][y] = data[x][y-1];
data[x][y-1] = 0;
y--;
step++;
//调用方法按照最新的数字加载图片
initimage();
}else if(code == 40 || code == 83){
System.out.println("向下移动");
//实现空白图片上方的图片向下移动
if (x == 0){
return;
}
data[x][y] = data[x-1][y];
data[x-1][y] = 0;
x--;
step++;
//调用方法按照最新的数字加载图片
initimage();
}else if(code == 73){
//当松开I键时,初始化界面
initimage();
}else if(code == 66){
//当按下键为B时,作弊
data = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initimage();
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == restartjmi){
System.out.println("重新游戏");
//计步器清零
step = 0;
//初始化数据
initdata();
//初始化图片
initimage();
}
// else if(obj == relogjmi){
// System.out.println("重新登录");
// //关闭当前游戏界面
// this.setVisible(false);
// //打开登陆界面
// new LoginJFrame();
// }
else if(obj == closejmi){
System.out.println("关闭游戏");
//关闭虚拟机
System.exit(0);
}else if(obj == accountjmi){
System.out.println("名片");
JDialog jdi = new JDialog();
JLabel jb = new JLabel(new ImageIcon("image\\mingpian.jpg"));
//设置位置
jb.setBounds(0,0,300,299);
jdi.getContentPane().add(jb);
//设置弹框大小
jdi.setSize(344,344);
//设置弹框置顶
jdi.setAlwaysOnTop(true);
//设置弹框居中
jdi.setLocationRelativeTo(null);
//设置弹框不关闭无法继续
jdi.setModal(true);
//设置弹框可视化
jdi.setVisible(true);
}else if (obj == girl) {
System.out.println("更换美女图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\girl\\girl";
changei();
}else if (obj == animal) {
System.out.println("更换动物图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\animal\\animal";
changei();
}else if (obj == sport) {
System.out.println("更换运动图片");
//计步器清零
step = 0;
//初始化数据
initdata();
//随机图片库
temppath = "\\sport\\sport";
changei();
}
}
}
成品展示: