Java 高手速成 | 实现人物拼图游戏

拼图游戏指将一幅图片分割成若干拼块,并随机打乱顺序,当将所有拼块都放回原位置时就完成了拼图(游戏结束)。
01、游戏介绍
在游戏中,拼块以随机顺序排列,网格上有一个位置是空的。完成拼图的方法是利用这个空位置移动拼块,玩家通过单击空位置周围的拼块来交换它们的位置,直到所有拼块都回到原位置。拼图游戏的运行界面如图 1 所示。

▍图 1 拼图游戏的运行界面
02、程序设计的思路
在游戏中动态生成一个 3×3 的图片按钮数组 cells。将图片 woman.jpg 分割成行、列数均为 3 的小图片,并按顺序编号;每个图片按钮显示一幅小图片,其位置成员 place 存储 0~8 的数,代表正确的位置编号。注意,最后一个图片按钮显示的是空白信息图片“9.jpg”,而位置成员 place 存储 8。
在游戏开始时,随机打乱图片按钮数组 cells,根据玩家的单击来交换图片按钮数组 cells 对应按钮与空白图片按钮的位置,通过判断图片按钮数组 cells 中所有元素的位置成员 place 是否有序来判断是否已经完成游戏。
03、关键技术
1、按钮显示图片的实现
Swing 中的按钮可以显示图片(图像)。
JButton 中显示图片的构造方法为
JButton(Icon icon),用来在按钮上显示图片。
JButton 类的方法设置不同状态下按钮显示的图片。
setIcon(Icon defaultIcon):用来设置按钮在默认状态下显示的图片。
setRolloverIcon(Icon rolloverIcon):设置当鼠标指针移动到按钮上方时显示的图片。
setPressedIcon(Icon pressedIcon):设置当按钮被按下时显示的图片。
下面是一个控制鼠标指针移动到按钮上方及按钮被按下时显示不同图片的示例。


程序运行结果如图 2 和图 3 所示。

▍图 2 按钮被按下去时显示的图片

▍图 3 鼠标滚动时显示的图片
2、图片按钮移动的实现
当图片按钮移动后,按钮的坐标发生改变,此操作通过 setLocation()方法实现。setLocation()方法是从 Component 类继承的,其定义如下:
public void.setLocation(int x,int y)
其中,参数 x 是当前组件的左上角在父级坐标空间中新位置的 x 坐标,参数 y 是当前组件的左上角在父级坐标空间中新位置的 y 坐标。
3、从 BufferedImage 转化成 ImageIcon
BufferedImage 类是 java.awt.Image 的子类,在 image 的基础上增加了缓存功能。
ImageIcon 类是一个 Icon 接口的实现,它根据 Image 绘制 Icon,可使用 URL、文件名或字节数组创建的图像。
从 BufferedImage 转化成 ImageIcon 只需要使用“ImageIcon im=new ImageIcon(BufferedImage 实例)”。
另外,使用 ImageIcon 的 Image getImage()方法返回此图标的 Image。
04、程序设计的步骤
项目组成如图 4 所示。

▍图 4 项目组成
1、设计单元图片类
创建名称为 Cell 的类,用于封装一个单元图片对象,此类继承 JButton 对象,并对 JButton 按钮组件进行重写,其代码如下:

2、创建枚举类型
在项目中创建一个名称为 Direction 的枚举类型,用于定义图片移动的 4 个方向。

3、设计游戏面板类
在项目中创建一个名称为 GamePanel 的类,此类继承 JPanel 类,实现 MouseListener 接口,用于创建游戏面板对象。在 GamePanel 类中定义长度为 9 个单元的图片数组对象 cells,并通过 init()方法对所有单元图片对象进行实例化。

构造方法 GamePanel()调用 init()对所有单元图片对象进行实例化。在对单元图片对象进行实例化时可以直接用分割好的图片 1.jpg~9.jpg(如图 9.5 所示)实现,其中 9.jpg 为空白图片。

▍图 5 拼图所用图片
单元图片对象直接用现成的分割好的图片进行实例化,代码如下:

当然也可以不用现成的分割好的图片,使用 BufferedImage 类的 getSubimage()方法可以将一个大的图片 woman.jpg 任意分割成子图像。

在使用时先得到一幅原图片的长和宽,根据要求分块,算出每块的 x、y 坐标,这样就可以分割了。注意,分割出来的是 BufferedImage 对象,而按钮的图片需要 ImageIcon 类型,从 BufferedImage 转化成 ImageIcon 只需要使用 ImageIcon im=new ImageIcon(BufferedImage 对象)。


random()对图片进行随机排序,产生两个随机数 m、n(0~8)作为被交换图片按钮数组 元素的下标,对调这两个被交换图片按钮的位置。


在图片块单击事件中,通过 e.getSource()获取触发事件的对象 cell,与空白图片块 cellBlank 的位置进行比较,从而决定被单击对象 cell 和空白图片块 cellBlank 的移动方向。

isSuccess()判断游戏是否成功,只需要判断图片块的原始位置 cells[i].getPlace()是否符合现在的位置,只要有一个单元图片的位置不正确就返回 false,所有单元图片的位置都正确时返回 true。

4、设计主窗口类
在项目中创建一个继承 JFrame 的 MainFrame 类,用于显示自定义游戏面板(GamePanel)。

拼图游戏的总体设计情况如上,并没有很高深的内容,实现的核心在于对按钮数组的操作。拼图游戏成功的效果如图 6 所示。

▍图 6 游戏成功的效果
版权声明: 本文为 InfoQ 作者【TiAmo】的原创文章。
原文链接:【http://xie.infoq.cn/article/69af35cc6bb299cef923e2441】。文章转载请联系作者。
评论