1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > java对拼图小游戏的简单实现(详解)

java对拼图小游戏的简单实现(详解)

时间:2021-06-27 16:12:16

相关推荐

java对拼图小游戏的简单实现(详解)

使用Java编写拼图小游戏主要包括:

初始化界面初始化菜单初始化数据初始化图片其他必要功能的实现

这几部分。在进行细分时包括了菜单的搭建,添加图片,打乱图片位置,让图片移动起来,查看完整图片,设置作弊码,判断胜利,实现计步功能,让整个界面显示出来等,下面来进行详细的讲解。

注:在进行代码的编程时,最好是把相同功能的代码写到同一个方法中,能够增强代码的阅读性以及方便之后修改代码

初始化界面

在初始化界面时要获取到界面,由于类中继承了JFrame父类,获得有默认界面窗口,可以使用this表示本类

设置界面的标题,设置界面置顶(防止其他界面覆盖游戏界面),设置界面居中(使界面出现在屏幕中央,否则界面会默认出现在屏幕左上角),

设置关闭模式,关闭模式使用setDefaultCloseOperation()方法,一共有三种为:括号里面分别填写DO_NOTHING_ON_CLOSE(可以用0代替),表示什么都不做,既不关闭界面,也不停止运行;填写HIDT_ON_CLOSE(可以用1代替)表示默认的窗口关闭操作,可以关闭窗口,不能停止运行;填写DISPOSE_ON_CLOSE(可以用2代替)表示如果开启了多个界面,只有关闭了最后的界面,虚拟机才会停止运行;填写EXIT_ON_CLOSE(可以用3代替),表示只要关闭了此界面,整个虚拟机就会停止

取消组件的默认居中放置,,由于需要在界面中进行游戏操作,还要在界面中添加一个键盘监听事件

代码为:

private void initJFrame() {//设置界面的宽高this.setSize(603,680);//设置界面的标题this.setTitle("拼图单机版 v1.0");//设置页面置顶this.setAlwaysOnTop(true);//设置页面居中this.setLocationRelativeTo(null);//设置关闭模式this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//取消默认居中放置的方法//只有取消了默认居中放置,才会按照xy轴的方式添加组件this.setLayout(null);//给整个界面添加键盘监听事件this.addKeyListener(this);}

初始化菜单 先创建JMenuBar对象再创建JMenu对象再创建JMenuItem对象把JMenuItem放到JMenu里面,再把JMenu放到JMenuBar里面最后把JMenuBra添加到整个JFrame界面中

JFrame:最外层的窗体(当创建JFrame对象时,就会出现窗口)

JMenuBra:最上层的菜单(:java中专门用来描述菜单的类)

JLabel:文字和图片的管理容器

添加图片

图片对应的类叫做ImageIcon,一张图片对应一个ImageIcon的图像,如果要给图片设置宽高,位置,边框等,需要把图片放到JLable中

在设置图片的位置时,使用setBound方法,以界面左上角为原点,水平向右为x轴,竖直向下为y轴,通过更改x,y的坐标可以改变图片的位置

代码为:

private void initImage(){//创建一个图片ImageIcon的对象ImageIcon icon = new ImageIcon("图片的详细位置");//创建一个JLable的对象(管理容器)JLable jLable = new JLable(icon);//表示这个管理容器就管理icon这个对象//可以简写://JLable jLable = new JLable(new ImageIcon("图片详细地址"));//指定图片的位置jLable.setBounds(105, 0, 105, 105);//分别表示x,y轴,宽,高//把管理容器添加到界面中this.add(jLable);//表示添加jLable这个图片}

由于每添加一张图片都要创建一个ImageIcon,过于繁琐,可以使用循环的方法简化代码

在添加了图片后,图片会默认放在界面正中央的位置,需要先使用setLayout方法,取消图片的默认居中放置,才能更改图片的位置

在初始化图片时,先使用getContentPane方法获取隐藏容器(在创建JFrame对象时自动创建出来了),用来装载组件,在调用add方法把图片添加到隐藏容器中

找不到的图片系统会默认以空白补上

代码为:

private void initImage(){int number = 1;//外循环--把内循环重复执行了四次for(int i = 0; i<4; i++){for(int j = 0; j<4; j++){//创建一个JLabel对象(管理容器)//详细位置中number的使用:把图片前的数字变成"+number+"JLabel jlabel = new JLabel(new ImageIcon("详细位置"));//指定图片位置jLabel.setBounds();//括号里面填x轴,y轴,宽,高对应的数据//先获取到隐藏的容器,再把管理容器添加给隐藏容器中this.getContentPane().add(jLabel);//添加一次之后number需要自增number++; } }

打乱图片的位置

原理:每张图片代表一个数字,空白图片代表0,把这些数字组成一个数组,打乱这个数组中的数字,同时把这些数字分成4组,组成一个二维数组,根据数组定义图片

private void initData() {int[] arr ={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 < arr.length; i++) {int index = r.nextInt(arr.length);//打乱图片顺序int a = arr[index];arr[index] = arr[i];arr[i] = a;}//便利一维数组得到每一个元素,把每一个元素依次添加到二维数组中for(int i = 0; i < arr.length; i++) {arrs[i / 4][i % 4] = arr[i];}

让图片移动起来

事件:可以被组件识别的操作,当组件做了某些事以后,就会执行对应的代码

事件中的三个要素:

事件源:按钮,图片,窗体等事件:(对事件源进行的操作)某些操作:如,鼠标单击,鼠标划入等绑定监听:事件源发生了某些事件,就会执行某段代码。。监听有KeyListener(键盘监听),MouseListener(鼠标监听),ActionListener(动作监听)

通过给组件绑定相应的监听事件,当组件出现了相应动作,就会执行相应代码

绑定监听事件是一个接口,在实现接口后要重写接口内所有的方法

//松开按键时会调用这个方法@Overridepublic void keyReleased(KeyEvent e) {//为了避免游戏结束后仍然可以使图片一定,需要进行判断//如果游戏胜利,这个方法直接结束,不能再执行下面的移动代码if(victory()){//return的作用,返回结果,结束方法return;}//对上下左右进行判断//左:37 上:38 右:39 下:40int code = e.getKeyCode();if(code == 37){//进行判断,空白图片在最最右方时,直接结束方法if (y == 3){return;}// 把空白方块的数字往右移动,左边的数字互换位置//x,y-1;表示另一个数字//把带图的数字赋值给不带图的arrs[x][y] = arrs[x][y+1];//之后原来带图的数字的标号变成0arrs[x][y+1] = 0;y++;//每移动一次,计步器就自增一次step++;initImage();System.out.println("向左移动");}else if(code == 38){if (x == 3){return;}arrs[x][y] = arrs[x+1][y];arrs[x+1][y] = 0;//每移动一次,计步器就自增一次step++;//x++表示在后来空白图片的位置xyx++;//调用方法,按照最新的数字加载图片initImage();System.out.println("向上移动");}else if(code == 39){if(y == 0){return;}arrs[x][y] = arrs[x][y-1] ;arrs[x][y-1] = 0;//每移动一次,计步器就自增一次step++;y--;initImage();System.out.println("向右移动");}else if(code == 40){if(x == 0){return;}arrs[x][y]= arrs[x-1][y];arrs[x-1][y] = 0;//每移动一次,计步器就自增一次step++;x--;initImage();System.out.println("向下移动");

美化界面

调整游戏界面的位置,给游戏界面添加背景颜色,添加游戏界面的边框

调整游戏界面的位置:指定游戏的位置时,在xy轴的位置添加像素,能把该图片再进行移动

原来:jLable.setBounds(105*j, 105*i, 105, 105);移动:jLable.setBounds(105*j+83, 105*i+134, 105, 105);

设置背景图片

添加图片在初始化图片中添加

代码加载图片时先加载的图片在上方(最外层),后加载的图片在下方(内层)

//添加背景图片JLabel background = new JLabel(new ImageIcon("背景图片的位置"));background.setBounds(40, 40, 508, 560);//把背景图片添加到界面当中//this表示当前的界面对象this.getContentPane().add(background);

给图片添加边框

调用setBoder方法,Border是一个接口,规定边框的规则,BevelBorder表示斜面边框

0表示让图片凸起来,RAISED

1表示让图片凹进去,LOWERED

先new一个斜面边框的对象,BevelBorder.LOWERED和BevelBorder.RAISED可以用1和0表示

jLable.setBorder(new BevelBOrder(BevelBorder.LOWERED));

查看完整图片,作弊码和判断胜利

查看完整图片:按住A不松,显示完整图片,松开A显示随机打乱的图片

在重写的键盘监听事件中进行

@Overridepublic void keyPressed(KeyEvent e) {int code = e.getKeyCode();if(code == 65){//把界面中的所有图片全部删除this.getContentPane().removeAll();//加载第一张完整图片JLabel all = new JLabel(new ImageIcon("完整图片的位置"));//设定图片的位置all.setBounds(83, 134, 420, 420);//调用出隐藏容器并把图片放进去this.getContentPane().add(all);

设置作弊码:

在释放按键执行的代码中,重新定义二维数组,二维数组为正确排序的顺序,,如果释放了w键,则按照更改后的二维数组重新加载图片,w代表的数据为87

if(code == 87){/*获取如果释放w键后,直接通关* 重新给arrs这个二维数组赋值* 二维数组为固定的* 之后重新加载图片*/arrs = new int[][]{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};//按照新定义的数组重新加载图片initImage();

设置通关胜利画面:

定义一个正确的二维数组win(在成员变量的地方)

在加载图片之前,先判断一下二维数组中的数字跟win数组中是否相同(定义一个方法进行判断)如果相同,显示正确图标如果不同则不显示

定义正确的二维数组(在成员变量的位置)

int[][] win = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};

​​​​重新定义一个方法,用来判断arrs数组与win数组是否相同

//判断目前数组中的数据与win数组中的相同//如果相同,返回true。否则返回falsepublic boolean victory(){for(int i = 0; i<arrs.length; i++){//i:依次表示二维数组arrs里面的索引//arrs[i]表示每一个一维数组for(int j = 0; j<arrs[i].length; j++){if(arrs[i][j] != win[i][j]){//只要有一个数据不一样,就返回falsereturn false;}}}//循环结束以后,数组遍历比较完,数据全部一样则返回truereturn true;}

在初始化图片的位置

添加胜利的图标

//调用比较数组的方法,对结果进行判断if(victory() == true){//显示胜利的图标//创建一个JLable对象JLabel winJLabel = new JLabel(new ImageIcon("jigsaw\\素材\\image\\win.png"));//给胜利的图标设置位置winJLabel.setBounds(203,283, 197, 73);//让胜利的图标显示出来this.getContentPane().add(winJLabel);}

计步功能

定义一个变量,统计已经玩了多少步(在成员中定义变量,如果定义在方法中,变量每在方法调用后都会重新使用定义值)每次按上下左右的时候计步器自增一次

定义成员变量表示计步器,在初始化图片中设置计步器的位置宽高等,在KeyReleased方法中设置使计步器自增

在initImage中进行定义:

//把计步器加载到界面//创建一个JLabel对象JLabel stepCount = new JLabel("步数:"+step);//设置位置和宽高stepCount.setBounds(50, 30, 100, 20);//使图片显示出来this.getContentPane().add(stepCount);

重新游戏

给重新游戏绑定事件:可以绑定MouseListener鼠标监听事件(包含点击,划入,划出,松开,单击,,单击是点击松开后自动补充的),也可以绑定ActionListener动作监听事件(包含鼠标点击和空格两个功能)

:::实现接口,重写方法:在GameJFrame类中,实现ActionListener接口,并重写接口中的抽样方法

重新打乱二维数组中的数字(重新游戏使用)加载图片计步器清零

if(obj == replayItem){//计步器清零step = 0;//再次打乱二维数组中的数据initData();//重新加载图片initImage();System.out.println("重新游戏");

关闭游戏

给关闭游戏绑定事件结束虚拟机,关闭所有

else if(obj == closeItem){System.out.println("关闭游戏");//直接关闭虚拟机System.exit(0);

完整代码::

package 验证;/*需求::* 设置更换图片的事件* 给条目绑定这个事件*/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 {public static void main(String[] args){new GameJFrame();}//JFrame表示界面或者窗口//子类也表示界面或者窗口//规定:GameJFrame这个界面就是游戏的主界面//以后跟游戏相关的所有逻辑写在这个类中//定义一个二维数组,存储正确的数字int[][] win = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};// 创建选项下条目的对象,,,创建对象的代码JMenuItem replayItem = new JMenuItem("重新游戏");JMenuItem closeItem = new JMenuItem("关闭游戏");JMenuItem accountItem = new JMenuItem("公众号");//定义一个变量,记录当前显示的图片路径//如果要更改图片可以直接更改path记录的值String path = "jigsaw\\素材\\image\\animal\\animal3\\" ;//定义一个方法,表示需要随机抽取的图片//只需要获取路径中的随机图片//需要用到动作监听事件//记录空白放块在二维数组中的位置int x = 0;int y = 0;//定义一个变量用来统计步数int step = 0;// 创建一个二维数组//用来管理数据,在加载图片是要根据二维数组中的数据进行加载//在下面两个方法里面都会用到数组,因此应该写在成员位置int[][] arrs = new int[4][4];//写一个构造方法public GameJFrame(){//初始化界面initJFrame();//初始化菜单initJMenuBra();//初始化数据(打乱)initData();//初始化图片(根据打乱的结果加载图片)initImage();//ran让界面显示出来,建议写在最后this.setVisible(true);}//初始化数据,采用打乱的方式//初始化图片//添加图片是要按照二维数组中管理的数据添加图片private void initData() {//定义一个一维数组int[] arr ={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 < arr.length; i++) {//获取到随机索引int index = r.nextInt(arr.length);//拿遍历到地每一个数据跟随机索引地数据进行交换,// 这样即便获得的随机数有一样的数// 交换顺序后相同数的个数不会改变// 造成的结果只是数组中同一个数进行了多次交换// 交换之后顺序打乱int a = arr[index];arr[index] = arr[i];arr[i] = a;}//便利一维数组得到每一个元素,把每一个元素依次添加到二维数组中for(int i = 0; i < arr.length; i++) {if (arr[i] == 0){x = i/4;y = i%4;}arrs[i / 4][i % 4] = arr[i];}}//初始化图片方法,在上面进行调用//由于上面打乱了二维数组的数据,在添加图片的时候就要按照二维数组管理的数据添加图片private void initImage() {//路径的分类//绝对路径:一定从盘符开始。C:\//相对路径:不是从盘符开始的,//相对路径相对当前的项目而言,如:aaa\\bbb//在当前项目下,去找aaa文件夹,里面再找bbb文件夹//清空原本出现的图片this.getContentPane().removeAll();//调用比较数组的方法,对结果进行判断if(victory() == true){//显示胜利的图标//创建一个JLable对象JLabel winJLabel = new JLabel(new ImageIcon("jigsaw\\素材\\image\\win.png"));//给胜利的图标设置位置winJLabel.setBounds(203,283, 197, 73);//让胜利的图标显示出来this.getContentPane().add(winJLabel);}//把计步器加载到界面//创建一个JLabel对象JLabel stepCount = new JLabel("步数:"+step);//设置位置和宽高stepCount.setBounds(50, 30, 100, 20);//使图片显示出来this.getContentPane().add(stepCount);// int number = 1;//加载图片时,先加载的图片在上方(外层),//后加载的图片在下方(内层)//按照二维数组的数字添加图片//外循环,表示要添加四行图片for (int j = 0; j<4; j++) {//内循环,表示在一行要添加4行图片for (int i = 0; i<4; i++){//获取加载图片的序号int nums = arrs[j][i] ;//创建JLabel对象(管理容器),并把图片放进去JLabel jLabel = new JLabel(new ImageIcon(path+""+nums+".jpg"));//指定图片的位置jLabel.setBounds(105*i+83, 105*j+134, 105, 105);//给图片添加边框//0表示让图片凸起来RAISED//1表示让图片凹进去LOWEREDjLabel.setBorder(new BevelBorder(BevelBorder.RAISED));//把管理容器添加到隐藏界面中this.getContentPane().add(jLabel);}}//添加背景图片JLabel background = new JLabel(new ImageIcon("jigsaw\\素材\\image\\background.png"));background.setBounds(40, 40, 508, 560);//把背景图片添加到界面当中//this表示当前的界面对象this.getContentPane().add(background);//刷新界面this.getContentPane().repaint();}//初始化菜单private void initJMenuBra() {//创建整个菜单对象JMenuBar JMenuBra = new JMenuBar();//创建菜单上两个选项的对象(功能 关于我们)设置选项JMenu functionJMenu = new JMenu("功能");JMenu aboutJMenu = new JMenu("关于我们");JMenu changeImage = new JMenu("更换图片");//把每一个选项下的条目接收到选项中functionJMenu.add(replayItem);//使用add方法调用replayItemfunctionJMenu.add(closeItem);aboutJMenu.add(accountItem);//给条目绑定事件//使用对象调用方法执行this本类中的代码replayItem.addActionListener(this);closeItem.addActionListener(this);accountItem.addActionListener(this);//把菜单中的两个选项添加到菜单当中JMenuBra.add(functionJMenu);JMenuBra.add(aboutJMenu);JMenuBra.add(changeImage);//给整个界面设置菜单//使用方法//this表示当前的界面对象,调用set方法'this.setJMenuBar(JMenuBra);}//初始化界面private void initJFrame() {//设置界面的宽高this.setSize(603,680);//设置界面的标题this.setTitle("拼图单机版 v1.0");//设置页面置顶this.setAlwaysOnTop(true);//设置页面居中this.setLocationRelativeTo(null);//设置关闭模式// this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//取消默认居中放置的方法//只有取消了默认居中放置,才会按照xy轴的方式添加组件this.setLayout(null);//给整个界面添加键盘监听事件this.addKeyListener(this);}@Overridepublic void keyTyped(KeyEvent e) {}//按下不松时调用的方法@Overridepublic void keyPressed(KeyEvent e) {int code = e.getKeyCode();if(code == 65){//把界面中的所有图片全部删除this.getContentPane().removeAll();//加载第一张完整图片JLabel all = new JLabel(new ImageIcon(path+"all.jpg"));//设定图片的位置all.setBounds(83, 134, 420, 420);//调用出隐藏容器并把图片放进去this.getContentPane().add(all);//加载背景图片JLabel background = new JLabel(new ImageIcon("jigsaw/素材/image/background.png"));//设置背景图片的位置background.setBounds(40, 40, 508, 560);//把背景图片添加到界面中this.getContentPane().add(background);//刷新界面this.getContentPane().repaint();}}//松开按键时会调用这个方法@Overridepublic void keyReleased(KeyEvent e) {//为了避免游戏结束后仍然可以使图片一定,需要进行判断//如果游戏胜利,这个方法直接结束,不能再执行下面的移动代码if(victory()){//return的作用,返回结果,结束方法return;}//对上下左右进行判断//左:37 上:38 右:39 下:40int code = e.getKeyCode();if(code == 37){//进行判断,空白图片在最最右方时,直接结束方法if (y == 3){return;}// 把空白方块的数字往右移动,左边的数字互换位置//x,y-1;表示另一个数字//把带图的数字赋值给不带图的arrs[x][y] = arrs[x][y+1];//之后原来带图的数字的标号变成0arrs[x][y+1] = 0;y++;//每移动一次,计步器就自增一次step++;initImage();System.out.println("向左移动");}else if(code == 38){if (x == 3){return;}//把空白方块下方的数字往上移动// xy表示空白方块//x+1,y表示空白方块下方的数字//把空白方块下方的数字赋值给空白方块arrs[x][y] = arrs[x+1][y];arrs[x+1][y] = 0;//每移动一次,计步器就自增一次step++;//x++表示在后来空白图片的位置xyx++;//调用方法,按照最新的数字加载图片initImage();System.out.println("向上移动");}else if(code == 39){if(y == 0){return;}//令左边的图片右移//把左边图片的标号与0互换//再次记录空白图片的位置arrs[x][y] = arrs[x][y-1] ;arrs[x][y-1] = 0;//每移动一次,计步器就自增一次step++;y--;initImage();System.out.println("向右移动");}else if(code == 40){if(x == 0){return;}//令空白图片上面的图片下移//令空白图片与其上方图片的标号互换//再次记录空白图片的数组表示,由于只有y变了,只改变y的值就可以了arrs[x][y]= arrs[x-1][y];arrs[x-1][y] = 0;//每移动一次,计步器就自增一次step++;x--;initImage();System.out.println("向下移动");}else if(code == 65){initImage();}else if(code == 87){/*获取如果释放w键后,直接通关* 重新给arrs这个二维数组赋值* 二维数组为固定的* 之后重新加载图片*/arrs = new int[][]{{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};//按照新定义的数组重新加载图片initImage();}}//判断目前数组中的数据与win数组中的相同//如果相同,返回true。否则返回falsepublic boolean victory(){for(int i = 0; i<arrs.length; i++){//i:依次表示二维数组arrs里面的索引//arrs[i]表示每一个一维数组for(int j = 0; j<arrs[i].length; j++){if(arrs[i][j] != win[i][j]){//只要有一个数据不一样,就返回falsereturn false;}}}//循环结束以后,数组遍历比较完,数据全部一样则返回truereturn true;}@Overridepublic void actionPerformed(ActionEvent e) {//获取当前的条目对象Object obj = e.getSource();//判断当前点击的是谁if(obj == replayItem){/** 重新加载图片中用到了计步器,应该把计步器清零放到重新加载图片的上面* 打乱数组中的代码要进行改动:* 原来0序号的数组没有进行赋值,更改为进行赋值的情况,防止出现重新开始加载图片时没有空白图片的现象*///计步器清零step = 0;//再次打乱二维数组中的数据initData();//重新加载图片initImage();System.out.println("重新游戏");}else if(obj == closeItem){System.out.println("关闭游戏");//直接关闭虚拟机System.exit(0);}else if(obj == accountItem){System.out.println("公众号");/*以弹框的形式出现* 弹框里面加了一张公众号* *///创建一个弹框对象JDialogJDialog jDialog = new JDialog();//创建一个管理图片的容器对象JLabelJLabel jLabel = new JLabel(new ImageIcon("jigsaw\\素材\\image\\about.png"));//设置位置和宽高,相对有弹框而言的,表示要把jLabel放在弹框那里jLabel.setBounds(0, 0, 258, 258);//把图片添加到弹框当中jDialog.getContentPane().add(jLabel);//给弹框设置大小jDialog.setSize(344,344);//让弹框置顶,diao调用方法AlwaysOnTop,kuo括号里面填写truejDialog.setAlwaysOnTop(true);//让弹框居中jDialog.setLocationRelativeTo(null);//弹框不关闭则无法操作下面的界面jDialog.setModal(true);//让弹框显示出来jDialog.setVisible(true);}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。