【进阶篇-Day4:使用JAVA编写石头迷阵游戏】

在这里插入图片描述

1、绘制界面

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

上述思路是:使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。

在这里插入图片描述

在这里插入图片描述

代码如下:

package com.itheima.stonepuzzle;
import javax.swing.*;

public class MainFrame extends JFrame {
    //data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。
    int[][] data = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };

    /**
     * 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,
     * 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,
     * 所以在构造方法里调用即可
     */
    public MainFrame(){
        //初始化窗体
        initFrame();
        //绘制游戏界面
        paintView();
        //设置窗体可见
        setVisible(true);
    }

    /**
     * 此方法用于窗体初始化
     */
    public void initFrame(){
//        JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用
        //设置窗体大小
        setSize(514, 595);
        //设置窗体关闭模式:关闭窗口时,结束程序
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        //设置窗体标题
        setTitle("石头迷阵单机版V1.0");
        //设置窗体永在最上层
        setAlwaysOnTop(true);
        //设置窗体居中
        setLocationRelativeTo(null);
        //设置取消默认布局
        setLayout(null);
    }

    /**
     * 此方法用于绘制游戏的界面
     */
    public void paintView(){
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));
                //设置图片对象大小
                jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
                //将图片对象塞进窗体
                getContentPane().add(jl);
            }
        }
        
        JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));
        //设置图片对象大小
        background.setBounds(26, 30, 450, 484);
        //将图片对象塞进窗体
        super.getContentPane().add(background);
    }
}

运行代码,绘制界面的结果如下:
在这里插入图片描述

2、打乱石头方块

在这里插入图片描述

代码:

/**
 * 初始化数据(随机打乱石头)
 */
public void initData(){
    Random r = new Random();
    //1、遍历二维数组,获取每一个元素
    for (int i = 0; i < data.length; i++) {
        for (int j = 0; j < data[i].length; j++) {
            //2、随机获取 (x坐, y坐标),找到其中一个数
            int x = r.nextInt(4);//x坐标
            int y = r.nextInt(4);//y坐标
            //3、将当前遍历到的元素,和随机获取到的元素做交换
            int temp = data[i][j];
            data[i][j] = data[x][y];
            data[x][y] = temp;
        }
    }
}

3、移动业务

在这里插入图片描述

    /**
     * 按下键盘时出发事件
     * @param e
     */
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        move(keyCode);
    }

    /**
     * 此方法用于处理移动业务
     * @param keyCode
     */
    private static void move(int keyCode) {
        if (keyCode == 37){
            System.out.println("左移动业务...");
        } else if (keyCode == 38) {
            System.out.println("上移动业务...");
        } else if (keyCode == 39) {
            System.out.println("右移动业务...");
        } else if (keyCode == 40) {
            System.out.println("下移动业务...");
        }
    }

在这里插入图片描述

移动石头块,实际上只需要交换二维数组中的两个数即可,然后再刷新就实现了移动业务。

做法:
在这里插入图片描述
在这里插入图片描述

//寻找0号元素的位置
lo:
for (int i = 0; i < data.length; i++) {
    for (int j = 0; j < data[i].length; j++) {
        if (data[i][j] == 0) {
            row = i;
            col = j;
            break lo;
        }
    }
}

下面看下上、下、左、右移动:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:
在这里插入图片描述
在这里插入图片描述

/**
 * 此方法用于处理移动业务
 *
 * @param keyCode
 */
private void move(int keyCode) {
    int temp = data[row][col];//0号元素
    if (keyCode == 37 && col < 3) {
        System.out.println("左移动业务...");
        //左移动时,空白块和右边的数做交换
        data[row][col] = data[row][col + 1];
        data[row][col + 1] = temp;
        //记录0号元素的列坐标也要随之改变
        col++;
    } else if (keyCode == 38 && row < 3) {
        System.out.println("上移动业务...");
        //上移动时,空白块和下边的数做交换
        data[row][col] = data[row + 1][col];
        data[row + 1][col] = temp;
        //记录0号元素的列坐标也要随之改变
        row++;
    } else if (keyCode == 39 && col > 0) {
        System.out.println("右移动业务...");
        //右移动时,空白块和左边的数做交换
        data[row][col] = data[row][col - 1];
        data[row][col - 1] = temp;
        //记录0号元素的列坐标也要随之改变
        col--;
    } else if (keyCode == 40 && row > 0) {
        System.out.println("下移动业务...");
        //下移动时,空白块和上边的数做交换
        data[row][col] = data[row - 1][col];
        data[row - 1][col] = temp;
        //记录0号元素的列坐标也要随之改变
        row--;
    }else if (keyCode == 90){//z键
        //触发作弊器
        data = new int[][]{
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
        };
    }
    System.out.println(row + "," + col);
}

4、游戏判定胜利

在这里插入图片描述

/**
 * 判断游戏是否胜利
 * @return
 */
public boolean victory(){
    for (int i = 0; i < data.length; i++) {
        for (int j = 0; j < data[i].length; j++) {
            if(data[i][j] != win[i][j]){
                return false;
            }
        }
    }
    //运行到这里,表明游戏胜利了
    return true;
    }

在这里插入图片描述

5、统计步数

在这里插入图片描述

6、重新游戏

在这里插入图片描述

7、完整代码:

package com.itheima.stonepuzzle;

public class Test {
    public static void main(String[] args) {
    //启动器
        new MainFrame();
    }
}
package com.itheima.stonepuzzle;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class MainFrame extends JFrame implements KeyListener {
    //data使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。
    int[][] data = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };

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

    int row; //0号元素的行坐标
    int col; //0号元素的列坐标

    int count = 0;//记录操作的次数

    /**
     * 因为初始化窗体 和 绘制游戏界面,是在进入游戏就要执行的,
     * 因此只需要在new对象时执行即可,而new对象时构造方法一定会执行,
     * 所以在构造方法里调用即可
     */
    public MainFrame() {
        //键盘监听:
        //窗体对象.addKeyListener(KeyListener实现类对象)
        //this:当前对象,两个身份
        //1)窗体对象
        //2)KeyListener实现类对象
        this.addKeyListener(this);

        //初始化窗体
        initFrame();
        //初始化数据(随机打乱石头)
        initData();
        //绘制游戏界面
        paintView();
        //设置窗体可见
        setVisible(true);
    }

    /**
     * 此方法用于窗体初始化
     */
    public void initFrame() {
//        JFrame jf = new JFrame(); --因为此类继承了JFrame,因此下面的方法可以直接调用
        //设置窗体大小
        setSize(514, 595);
        //设置窗体关闭模式:关闭窗口时,结束程序
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        //设置窗体标题
        setTitle("石头迷阵单机版V1.0");
        //设置窗体永在最上层
        setAlwaysOnTop(true);
        //设置窗体居中
        setLocationRelativeTo(null);
        //设置取消默认布局
        setLayout(null);
    }

    /**
     * 初始化数据(随机打乱石头)
     */
    public void initData() {
        Random r = new Random();
        //1、遍历二维数组,获取每一个元素
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                //2、随机获取 (x坐, y坐标),找到其中一个数
                int x = r.nextInt(4);//x坐标
                int y = r.nextInt(4);//y坐标
                //3、将当前遍历到的元素,和随机获取到的元素做交换
                int temp = data[i][j];
                data[i][j] = data[x][y];
                data[x][y] = temp;
            }
        }

        //寻找0号元素的位置
        lo:
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] == 0) {
                    row = i;
                    col = j;
                    break lo;
                }
            }
        }
    }

    /**
     * 此方法用于绘制游戏的界面
     */
    public void paintView() {
        //每次绘制之前,都清空之前绘制的界面
        super.getContentPane().removeAll();

        //加载胜利图片资源,添加到窗体中
        if (victory()){
            JLabel victoryJl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\victory.jpg"));
            victoryJl.setBounds(124, 230, 266, 100);
            getContentPane().add(victoryJl);
        }

        //加载重新开始按钮
        if (count > 0){
            JButton jb = new JButton("重新开始");
            jb.setBounds(350, 10, 100, 20);
            jb.setFocusable(false);//取消焦点
            jb.addActionListener(new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //统计步数归0
                    count = 0;
                    //重新初始化数据
                    initData();
                    //重新绘制游戏界面
                    paintView();
                }
            });
            getContentPane().add(jb);
        }

        //加载记录步数组件
        JLabel stepJl = new JLabel("步数:" + count);
        stepJl.setBounds(50, 10, 100, 20);
        getContentPane().add(stepJl);

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                JLabel jl = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\" + data[i][j] + ".jpg"));
                //设置图片对象大小
                jl.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
                //将图片对象塞进窗体
                getContentPane().add(jl);
            }
        }

        //加载背景图
        JLabel background = new JLabel(new ImageIcon("C:\\Users\\MSZ\\Desktop\\java_test\\dev\\image\\background.jpg"));
        //设置图片对象大小
        background.setBounds(26, 30, 450, 484);
        //将图片对象塞进窗体
        super.getContentPane().add(background);

        //刷新
        super.getContentPane().repaint();
    }

    /**
     * 按下键盘时出发事件
     *
     * @param e
     */
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        move(keyCode);
        //判断是否胜利
        victory();
        //每次移动之后,都重新绘制游戏界面
        paintView();
    }

    /**
     * 此方法用于处理移动业务
     *
     * @param keyCode
     */
    private void move(int keyCode) {
        //如果游戏胜利了,则不允许操作
        if (victory()){
            return;
        }

        int temp = data[row][col];//0号元素
        if (keyCode == 37 && col < 3) {
//            System.out.println("左移动业务...");
            //左移动时,空白块和右边的数做交换
            data[row][col] = data[row][col + 1];
            data[row][col + 1] = temp;
            //记录0号元素的列坐标也要随之改变
            col++;
            count++;
        } else if (keyCode == 38 && row < 3) {
//            System.out.println("上移动业务...");
            //上移动时,空白块和下边的数做交换
            data[row][col] = data[row + 1][col];
            data[row + 1][col] = temp;
            //记录0号元素的列坐标也要随之改变
            row++;
            count++;
        } else if (keyCode == 39 && col > 0) {
//            System.out.println("右移动业务...");
            //右移动时,空白块和左边的数做交换
            data[row][col] = data[row][col - 1];
            data[row][col - 1] = temp;
            //记录0号元素的列坐标也要随之改变
            col--;
            count++;
        } else if (keyCode == 40 && row > 0) {
//            System.out.println("下移动业务...");
            //下移动时,空白块和上边的数做交换
            data[row][col] = data[row - 1][col];
            data[row - 1][col] = temp;
            //记录0号元素的列坐标也要随之改变
            row--;
            count++;
        }else if (keyCode == 90){//z键
            //触发作弊器
            data = new int[][]{
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12},
                {13, 14, 15, 0}
            };
            count++;
        }
//        System.out.println(row + "," + col);
    }

    /**
     * 判断游戏是否胜利
     * @return
     */
    public boolean victory(){
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if(data[i][j] != win[i][j]){
                    return false;
                }
            }
        }
        //运行到这里,表明游戏胜利了
        return true;
    }

    //-------------------------------------
    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
    //-------------------------------------
}

界面图片已放在资源里,可下载。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值