Java项目 拼图游戏

        目录

1 项目基本信息

1.1 项目名称

1.2 实训环境

2 实训内容简介

2.1 拼图游戏

3 项目开发过程

3.1 拼图游戏

3.1.1 核心类

3.1.2开发步骤

4 实训总结及心得

1 项目基本信息

1.1 项目名称

拼图游戏

1.2 实训环境

JDK1.8 、eclipse 、 mysql 、navicat、Windows

2 实训内容简介

2.1 拼图游戏

        拼图游戏内容由若干小图像块组成的,其中有一个空白的小图像块,该图像块是来与别的图像块交换的,以此来实现大图像的拼凑。在Java标准环境下运行,通过鼠标点击图像块上下左右移动,完成大图像的拼凑。通过所创建的窗体类、菜单、中间面板和左右面板完成设计拼图的交互界面,实现游戏登录、开始游戏、退出游戏、选择图片、图片缩放、图片分割、调整难易度、计数计时、打乱图片、判断拼图成功等功能。游戏可以通过对图片文件的读取和加载,从多张图片中选择来进行拼图游戏,通过设置图像块的个数来实现对游戏难易度的调整,最后将游戏完成后所用时间和步数记录到游戏记录中,方便用户查看游戏记录。

3 项目开发过程

3.1 拼图游戏

3.1.1 核心类

        1.MainJFrame类:继承JFrame类,实现Runnable接口,窗体用于存放发左右面板,添加组件等等。知识点有:

a.实现游戏关卡等级
itemeasy.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				rp.hs=2; //第一,传递2*2到右面板
				rp.ls=2;
				rp.init(url); //调用右面板组件初始化的方法
			}
		});
b. 游戏记录
itemchange.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
//显示一个打开对话框,选择一个图片文件,将文件转换为url对象,调用左右面板的相应方法
				JFileChooser jfc=new JFileChooser();
//设置文件的扩展名
				jfc.setFileFilter(new FileNameExtensionFilter("图片格式(jpg|png|jif)", "jpg","png","gif"));
//弹出打开对话框
				int sd=jfc.showOpenDialog(MainJFrame.this);//null表示父容器是谁
			if(sd==jfc.APPROVE_OPTION)//如果用户选择打开了按钮
				{
//获取用户选择的文件完整名称
			String file=jfc.getSelectedFile().getAbsolutePath();
					try {
						url=new URL("file:\\"+file);
						lp.init(url);
						rp.init(url);
					} catch (MalformedURLException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
		});
c. //记录清空
		itemclear.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				File f=new File("c://a");
				if(f.exists()){
					f.delete();
				}
			}
		});
d. 实现计时并显示步数
	@Override
	public void run() {
		//死循环,使得代码一直在执行
		while (true) {
			endTime = System.currentTimeMillis();
			total_time.setText("用时:"+(endTime - startTime) / 1000 );
			total_count.setText("步数:"+rp.times);
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

        2.LeftJPanel类:左面板,将完整图片展示在左面板。知识点:

实现图片的缩放:
public void init(URL url){
		ImageIcon icon=new ImageIcon(url);
		//使用链式编程方式实现图片缩放
		jl.setIcon(new ImageIcon(icon.getImage().getScaledInstance(width, height, 1)));
		//将标签添加到面板中
		this.add(jl);
	}

        3.RightJPanel类:右面板实现ActionListener接口,右面板成为了监听器,实现拼图。重要知识点:

a.确定按钮的位置和大小
bs=new JButton[hs*ls]; //创建按钮数组
widthbut=width/ls;// 计算按钮的宽度高度
	heightbut=height/hs;
for(int i=0;i<jbs.length;i++){//为每一个按钮实现初始化操作
		jbs[i]=new JButton();
		jbs[i].setSize(widthbut, heightbut);
	    jbs[i].setLocation(i%ls*widthbut,i/ls*heightbut);// 添加按钮前要确定坐标位置
b. //图片的获取
BufferedImage subimage=buf.getSubimage(i%ls*widthxt,i/ls*heightxt, widthxt, heightxt); //小图的获取
c. //图片的缩放
Image image=subimage.getScaledInstance(widthbut, heightbut, 1);
d. //将小图图片放到按钮上
jbs[i].setIcon(new ImageIcon(image));
e. //设置按钮变色,不可用
jbs[i].setEnabled(false);
f. //设置按钮的监听,当按钮被单击,找ActionListener方法执行
jbs[i].addActionListener(this);
g. //设置最后一个按钮图片为空
			jbs[hs*ls-1].setIcon(null);
			kb=jbs[hs*ls-1];
h. //打乱按钮在面板中的顺序
		Random rand=new Random();//创建随机数对象
		for(int i=0;i<hs*ls;i++){ //打乱多次 for
			//生成两个随机数表示数组下标,互换两个数组元素的位置
			int index1 = rand.nextInt(hs * ls);
			int index2 = rand.nextInt(hs * ls);
			// getX 和getY 可以获取按钮的坐标位置
			int x1 = jbs[index1].getX();
			int y1 = jbs[index1].getY();
			int x2 = jbs[index2].getX();
			int y2 = jbs[index2].getY();
			jbs[index1].setLocation(x2, y2);
			jbs[index2].setLocation(x1, y1);
			jbs[i].setEnabled(true);
		}
i. //获取用户单击的按钮,通过ActionEvent e的方法getSource获取事件源,需要将得到的object类型中转换为按钮类型
JButton jb=(JButton)e.getSource();
j. //获取单击按钮和空白按钮的坐标
		int x1=jb.getX();
		int y1=jb.getY();
		int x2=kb.getX();
		int y2=kb.getY();
k. //判断单击按钮和空白按钮是否相邻,相邻则位置互换
if(Math.abs((x1-x2)/widthbut)+Math.abs((y1-y2)/heightbut)==1){
			jb.setLocation(x2, y2);// 用Math.abs取绝对值
			kb.setLocation(x1, y1);
			times++;
		}
l. //判断是否拼图成功
		if(isWin()){
			JOptionPane.showMessageDialog(null, "恭喜,拼图成功,总共步数:"+times);
			//使得按钮不可用
			for(int i=0;i<jbs.length;i++){
				jbs[i].setEnabled(false);
			}
m. //创建文件字符输出流对象,指向c盘,追加数据到文件
String info=hs+"*"+ls+"拼图的记录:"+name+"步数是:"+times+"\r\n";
FileWriter fw=new FileWriter("c://a//1.dat",true);
				fw.write(info);
				fw.close();
n. //获取每个按钮的坐标
		for(int i=0 ; i<jbs.length;i++){
			int x=jbs[i].getX()/widthbut;
			int y=jbs[i].getY()/heightbut;
			//方法二:通过下标值,也可获取按钮坐标  横坐标:i%ls  纵坐标 i/ls
			if(i%ls!=x || i/ls!=y){
				return false;
			}
		}

        4.TpJFrame类:实现图片分割功能。知识点有:

a. //显示一个打开对话框,选择一个图片文件,将文件转换为url对象, 
				JFileChooser jfc=new JFileChooser();
b. //设置文件的扩展名
	jfc.setFileFilter(new FileNameExtensionFilter("图片文件", "jpg","bmp","jpeg"));
c. //获取用户选择的文件完整名称
jfc.getSelectedFile().getAbsolutePath()
	d.//获取图片后,将图片转换成Image类型的对象,进行缩放,然后再将Image类型对象转换成ImageIcon类型的对象,将图片放到jlb中
jlb.setIcon(new ImageIcon(new ImageIcon (jtf.getText()).getImage().getScaledInstance(100,100, 1)));
e. //从本地文本读取图片
		BufferedImage buf=ImageIO.read(new File(jtf.getText()));
f. //设置该面板标题
jp3.setBorder(BorderFactory.createTitledBorder("选择保存位置"));

3.1.2开发步骤

        1.配置开发环境,进行环境变量的配置:JAVA_HOME,path。

        2.创建窗体类MainJFrame,设置窗体大小、标题、窗体大小是否可变、窗体位置等等。在窗体内设置菜单、菜单项、单选菜单项等信息,并添加到窗体内。明确左面板、右面板、中间面板和窗体的关系:在窗体中设置一个中间面板,中间面板包括左面板和右面板。

        3.中间面板布局方式为网格布局。添加左面板和右面板:左面板(LeftJPanel)为自定义面板,继承JPanel;右面板(RightJPanel)为自定义面板,继承JPanel。

        4.左面板的设计:首先在主窗体中定义,将左面板添加到中间面板,再将中间面板添加到窗体,并进行初始化。然后在左面板类中添加一个标签,并在标签上显示图片,并实现图片缩放。

        在标签上显示图片的方法为:

ImageIcon(URL location)根据指定的 URL 创建一个 ImageIcon。

相对路径:url=this.getClass().getResource("s4.jpg");

绝对路径:url=new URL(“file:\\”+”d:\\abc\\1.jpg”);

        实现图片缩放的方法:图片放置在标签中,使用的类是ImageIcon,这个类没有缩放功能,Image类有缩放功能。所以要实现ImageIcon类和Image类相互转换。转换方法:

a.将ImageIcon的对象转换成Image类型的对象:public Image getImage()

icon.getImage().getScaledInstance(700,700,1)

b.将Image类型对象转换成ImageIcon类型的对象:ImageIcon的构造方法 ImageIcon(Image image)

        5.右面板的设计:首先在主窗体中定义,将右面板添加到中间面板,再将中间面板添加到窗体,并进行初始化。然后在右面板定义按钮数组、按钮大小及位置。然后进行图片分割,使图片显示在按钮上,在未点击开始按钮时使所有按钮变灰,不可用。设置最后一个按钮为空白按钮,方便单击按钮和空白按钮的相互转换。具体分析为:

a.首先分析按钮的大小和位置的关系,定义按钮的宽度和高度、按钮数组、行数和列数,在游戏未开始时,设置按钮不可见。
	bs=new JButton[hs*ls]; //创建按钮数组
widthbut=width/ls;// 计算按钮的宽度高度
	heightbut=height/hs;
for(int i=0;i<jbs.length;i++){//为每一个按钮实现初始化操作
		jbs[i]=new JButton();
		jbs[i].setSize(widthbut, heightbut);
	    jbs[i].setLocation(i%ls*widthbut,i/ls*heightbut);// 添加按钮前要确定坐标位置
		add(jbs[i]); //添加按钮到右面板
	jbs[i].setEnabled(false);// 使得按钮变灰色不可用
b.实现图片分割:使用ImageIO类对图片进行读写,然后使用BufferedImage类获取BufferedImage类的对象对图片进行分割,使用到的方法为:
读图片文件:public static BufferedImage read(URL input) throws IOException
写图片文件:public static boolean write(RenderedImage im, String formatName, File output) throws IOException
分割方法:public BufferedImage getSubimage(int x, int y, int w, int h)
代码:BufferedImage subimage=buf.getSubimage(i%ls*widthxt, i/ls*heightxt, widthxt, heightxt); //小图的获取
c.分割图片后,要对图片进行缩放。使用Image类中的getScaledInstance()方法对图片进行缩放。方法为:
public Image getScaledInstance(int width, int height,int hints)
代码: Image image=subimage.getScaledInstance(widthbut, heightbut, 1); //小图的缩放
d.最后添加一个空白按钮在右下角,为实现按钮的移动提供条件。
JButton kb; //空白按钮
jbs[hs*ls-1].setIcon(null); //设置最后一个按钮图片为空
kb=jbs[hs*ls-1];

        6.拼图完成后与左面板的原图比较进行判赢。设置不同游戏等级,可分为简单、一般、困难。若想更换图片,可进行图片的更换。

        a. 开始菜单单击时,执行具体操作只与右面板的组件相关,代码放到右面板类中

        通过改变按钮的坐标位置打乱按钮的顺序。方法是:生成两个随机数表示数组下标,互换两个数组元素的位置,按钮的方法getX和getY可以获取按钮的坐标。

相关代码:

 Random rand=new Random();//创建随机数对象

int index1 = rand.nextInt(hs * ls); /生成两个随机数表示数组下标,互换两个数组元素的位置

int index2 = rand.nextInt(hs * ls);

        b. 当对右面板中的按钮单击的时候,移动按钮。通过按钮的单击事件的处理,设置按钮的监听事件ActionListener,将代码写在监听事件中。代码为:

jbs[i].addActionListener(this); //设置按钮的监听,当按钮被单击,找ActionListener方法执行

        c.当用户拼图完成后,与原图进行比较判断是否拼图成功。判断拼图是否成功,主要取决于每一个按钮通过索引下标获取的位置值,与当前按钮的位置值是否相同。相关代码:

for(int i=0 ; i<jbs.length;i++){//获取每个按钮的坐标

int x=jbs[i].getX()/widthbut;

int y=jbs[i].getY()/heightbut;

if(i%ls!=x || i/ls!=y){

return false;

}

}

return true;

        d.设置游戏等级,即游戏的难易度。而游戏的难易度主要与右面板的行数和列数有关。可将行数hs和列数ls的值传给右面板,并对菜单进行监听和使用removeAll方法来清除所有组件来实现难易度。相关代码为:

rp.hs=2; //等级为简单时,传递2*2到右面板

rp.ls=2;



rp.init(url); //调用右面板组件初始化的方法

        e.在菜单项中有更换图片选项,用户可单击该菜单项,选择当前电脑中的图片文件,替换游戏中已有的图片。通过使用url数据的传递替换选择的图片,在两个面板中都起作用,即左面板的标签的背景图要换,右面板中的分割原图也要变。可通过监听事件实现,涉及的类有涉及到的类JFileChooser、FileNameExtendsionFilter,具体实现如下:

//显示一个打开对话框,选择一个图片文件,将文件转换为url对象,调用左右面板的相应方法
JFileChooser jfc=new JFileChooser();
//设置文件的扩展名
jfc.setFileFilter(new FileNameExtensionFilter("图片格式(jpg|png|jif)", "jpg","png","gif")); 
//null表示父容器是谁
int sd=jfc.showOpenDialog(MainJFrame.this); 
if(sd==jfc.APPROVE_OPTION)//如果用户选择打开了按钮
{  String file=jfc.getSelectedFile().getAbsolutePath();
//获取用户选择的文件完整名称
url=new URL("file:\\"+file);
		lp.init(url);
		rp.init(url);	}

        f.整个框架实现完成后,可设置计时和计数功能。

        计时:从单击开始菜单时计时开始,拼图成功计时结束。通过System类的currentTimeMillis ()方法,获取当前系统时间的毫秒值;通过线程的run()方法中,定时获取当前系统的时间点,线程的定义方法有两种:继承Thread类;实现Runnable接口,创建带实现接口的子类对象的Thread对象,重写run方法。通过公式(endTime-startTime)/1000计算出以秒为单位的时间段。

        计数:设置一个标签 total_count,使计数显示在菜单栏中,在设置一个计数功能 int times,判断按钮是否可以移动使times加1来实现计数功能。

        g.如果拼图成功,将信息记录到文件中,即菜单项中的游戏记录:显示用户之前的记录结果,读取文件并显示。通过FileWriter记录当前信息到文件中,FileReader读取文件。

        h.如果不想保留之前的记录,可将文件删除,即实现菜单项中的清空记录。相关代码为:

File f=new File("c://a");
		 if(f.exists()){
		 f.delete();

        7.可增加一个功能在菜单项中添加图片分割,新建一个TPJFrame类实现图片分割。

        a.新建窗口,在新窗口中设置组件四个面板,三个按钮,四个文本框和标题等等。

        b.首先通过单击选择图片按钮获取图片文件,将文件转换为url对象,获取用户选择的文件完整名称,获取图片后,将图片转换成Image类型的对象,进行缩放,然后再将Image类型对象转换成ImageIcon类型的对象,将图片放到jlb中。

4 实训总结及心得

见文档。

猜你喜欢

转载自blog.csdn.net/qq_70311894/article/details/131462730