上一篇博客,小编已经实现了拼图游戏的主界面的编写,但是对于拼图区的面板,预览区的面板还没有完成,在这篇博客,小编带着代码来完成剩下的代码,废话不多说,Let's Go!!!!
游戏拼图区
上图就是我们的游戏拼图区所要展示的效果,而且游戏拼图区就是一个JPanel, 我们会把游戏拼图区添加到我们的主界面类上:
我们主界面类MainFrame中PictureCanvasPanle就是我们的游戏拼图区.通过图1
的展示效果来分析我们的拼图区的类包含些什么?
从图1
我们很容易的知道,拼图区包含12个拼图小块,而且这12个拼图小块前11个是图片,最后一个是一个空白小块,为什么要空白小块呢? 这是因为如果全是图片,那我们就无法进行移动图片小块,进行拼图了, 所以最后的空白小块就是为了移动小块,当我们点击图片小块,就会把图片小块与空白小块进行切换,这样就实现了图片小块的移动效果了.
同样我们的图片小块也抽象成一个类: PictureCell,
public class PictureCell extends JButton {
private static final long serialVersionUID = -7205714777675652025L;
public PictureCell(Icon icon) {
super(icon);
this.setSize(150, 150);
}
public void move(String direction){
if(direction != null && !direction.isEmpty()){
switch(direction){
case "up":
this.setLocation(this.getBounds().x, this.getBounds().y - this.getHeight());
break;
case "right":
this.setLocation(this.getBounds().x + this.getWidth(), this.getBounds().y );
break;
case "down":
this.setLocation(this.getBounds().x, this.getBounds().y + this.getHeight());
break;
case "left":
this.setLocation(this.getBounds().x - this.getWidth(), this.getBounds().y );
break;
}
}
}
}
通过上述代码,我们发现拼图小块就是一个按钮, 而我们通过Icon这个类来展示图片.并且我们规定每个小块的大小是150*150,并定义了一个移动的方法:
我们来分析move的方法, up表示向上移动,通过上图,我们知道图片小块上移,就是把图片小块的y轴坐标,减去小块的高,就是移动后的图片小块的y轴坐标,而x轴坐标是不需要变的.
接下来我们来看我们的游戏拼图区的代码:
public class PictureCanvasPanle extends JPanel implements MouseListener {
private PictureCell[] cells = new PictureCell[12];
private Rectangle nullCell;
public static int stepNum = 0; // 步数
private boolean hasMouseListener = false;// 判断是否添加了鼠标监听, false 没有 true 有
//..未完
cells是我们用来存放12个拼图小块, nullCell作为空白小块,
接下来我们编写一个添加拼图小块的方法:
public void addCell() {
int length = cells.length;
int width = 0;
int height = 0;
for (int i = 0; i < length; i++) {
ImageIcon icon = new ImageIcon(
MainFrame.selectedPicture.getSubPicPaths()[i]);
if (i == 0) {
width = icon.getIconWidth();
height = icon.getIconHeight();
}
cells[i] = new PictureCell(icon); //添加图片
cells[i].setSize(width, height); //设置拼图小块的大小
cells[i].setLocation((i % 3) * width + 20, (i / 3) * height + 20); //小块的位置
this.add(cells[i]);
}
this.remove(cells[length - 1]); //移除最后一个图片小块
// 把空白的区域用一个矩形替换
nullCell = new Rectangle((11 % 3) * width + 20, (11 / 3) * height + 20,
width, height); //创建空白小块
}
在addCell()方法中,我们循环创建12个图片小块,并把最后一个图片小块删除,再创建一个空白小块
拼图小块创建好了之后,我们要把11个图片小块和空白小块打乱顺序:
/**
* 打乱小方块
*/
public void start() {
if (!hasMouseListener) {
for (int i = 0; i < cells.length - 1; i++) {
cells[i].addMouseListener(this);
}
// 更新鼠标监听状态
hasMouseListener = true;
}
// 第一个小方块不能位于左上角四个位置,如果在左上角四个位置,则需要进行小方块的移动
int width = cells[0].getWidth();
int height = cells[0].getHeight();
while (cells[0].getBounds().x <= width + 20
&& cells[0].getBounds().y <= height + 20) {
// 获取空方格的位置
int nullX = nullCell.getBounds().x;
int nullY = nullCell.getBounds().y;
// 随机产生一个空方格移动的方向 up, down, left right
int num = (int) (Math.random() * 4);
String direction = "";
switch (num) {
case 0: // 空方块往上移, 对应的方块往下移
direction = "down";
nullY -= height;
break;
case 1: // 空方块往右移, 对应的方块往左移
direction = "left";
nullX += width;
break;
case 2: // 空方块往下移, 对应的方块往上移
direction = "up";
nullY += height;
break;
case 3: // 空方块往左移, 对应的方块往右移
direction = "right";
nullX -= width;
break;
}
cellMove(nullX, nullY, direction);
}
}
打乱策略就是,我们不能让第一个小块位于我们拼图区的第一个位置,如果在第一个位置,我们就把空白小块随机与它周围的小块进行交换,并且一直循环下去,一直到第一个小块没有位于第一个位置,循环结束,打乱也就完成了.而且这个start() 方法绑定给主界面的start按钮的点击事件,单用户点击了start
触发点击事件,调用start()方法进行开始游戏.
接下来我们需要给游戏拼图区的JPanel绑定鼠标事件,用于操作拼图小块的移动:
/** 监听鼠标按下 */
@Override
public void mousePressed(MouseEvent e) {
// 获取点击的小方块
PictureCell btn = (PictureCell) e.getSource();
int clickX = btn.getBounds().x;
int clickY = btn.getBounds().y;
int width = btn.getWidth();
int height = btn.getHeight();
//获取空方格的坐标
int nullX = nullCell.getBounds().x;
int nullY = nullCell.getBounds().y;
if(clickX == nullX && clickY - nullY == -height){//点击的方块位于空方块的上面
btn.move("down");
}else if(clickX - nullX == width && clickY == nullY){//点击的方块位于空方块的右面
btn.move("left");
}else if(clickX == nullX && clickY - nullY == height){//点击的方块位于空方块的下面
btn.move("up");
}else if(clickX - nullX == -width && clickY == nullY){//点击的方块位于空方块的左面
btn.move("right");
}else{
return;
}
//移动空方格
nullCell.setLocation(clickX, clickY);
this.repaint();
stepNum++;
MainFrame.stepTxt.setText("步数:"+stepNum);
//判断是否完成
if(isFinished()){
JOptionPane.showMessageDialog(this, "恭喜您完成拼图,所用步数:"+stepNum);
for (int i = 0; i < cells.length - 1; i++) {
cells[i].removeMouseListener(this);
}
hasMouseListener = false;
}
}
拼图小块的移动就是先把拼图小块移动到空白小块上,然后把空白小块移动到拼图小块上:
最后我们还要编写一个判断拼图是否完成的方法:
private boolean isFinished() {
int width = cells[0].getWidth();
int height = cells[0].getHeight();
for (int i = 0; i < cells.length - 1; i++) {
int cellX = cells[i].getBounds().x;
int cellY = cells[i].getBounds().y;
if(((cellX-20)/width + (cellY-20)*3/height) != i ){
return false;
}
}
return true;
}
到此,我们的拼图区就已经完成了.接下来我们还要完成预览区的代码.
预览区
预览区的代码就比较简单,我们只需要把拼图区的完整图片画到预览区的Panel上.好了,不多说,直接上代码:
public class PicturePreviewPanel extends JPanel {
private String path;
public PicturePreviewPanel() {
super();
this.setBorder(new TitledBorder("预览区"));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(null == path || path.isEmpty()){
path = "image/1.jpg";
}
ImageIcon imageIcon = new ImageIcon(path);
Image image = imageIcon.getImage();
g.drawImage(image, 20, 15, 450, 600, this);
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
我们调用g.drawImage(image, 20, 15, 450, 600, this);
这行代码就把图片画到我们的面板上了.
此时我们已经完成了所有的编码,感谢各位看官老爷的阅读.
如果代码想要拼图的游戏的完整项目,请各位看官老爷移步到gitee上下载,下面就给各位看官老爷送上下载地址: