拼图游戏的实现2

        上一篇博客,小编已经实现了拼图游戏的主界面的编写,但是对于拼图区的面板,预览区的面板还没有完成,在这篇博客,小编带着代码来完成剩下的代码,废话不多说,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上下载,下面就给各位看官老爷送上下载地址:

suke_tan/拼图

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值