自学Java篇之JFrame创建《石头迷阵小游戏》

自学Java篇之JFrame创建《石头迷阵小游戏》

根据黑马程序员java教程自学完java基础,觉得石头迷阵小游戏案例具有一定的编程练习价值,记录之。

最终效果:

在这里插入图片描述

案例主要思想流程:

​ 主要是思想是创建一个4*4的二维数组data(初始化时打乱数组元素),存放石头编号,再根据编号(0,1,2…)进行imagelabel读取石头图片,组合展示到画板中。

​ 监听键盘上下左右间,根据键盘监听的数值进行if判断,将0编号的石头(即黑方块)根据上下左右对应的进行交换,即是对二维数组里的元素进行交换,交换一次就进行对二维数组展现一次(即刷新面板,重新展现一次石头,可以想成图片一帧帧切换)。

​ 根据移动到最后数组的元素等于胜利时的数组元素时,面板展示胜利图片,添加上步数统计,即监听键盘按了几次,以及重新开始按钮,即是对程序的重新运行,(打乱数组,重新展示。)

在这里插入图片描述

1、创建窗口完整框架:

​ 首先创建两个类,分别为MainFrame类和test类,前者用于游戏类的编写,后者用于运行游戏类代码。

MainFrame类:

package StonePuzzie;
import javax.swing.*;
import java.util.Random;
public class MainFrame extends JFrame {
    int[][] data = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };
//  MainFrame类创建自己构造方法:
    public  MainFrame(){
//        1、数据初始化
        initData();
//        2、初始化窗体
        initFrame();
//        3、绘制窗体
        painView();
//        设置窗口可见
        setVisible(true);
    }

    /**
     * chushi初始化数据(随机打乱二维数据)
     */
    public void initData(){
        /*
        创建rondom对象进行,随机生产x,y,用于确定data数组的下标,替换值,
        达到打乱数组顺序效果
         */
        Random r = new Random();
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                int randomX = r.nextInt(4);
                int randomY = r.nextInt(4);
                int temp = data[i][j]; data[i][j] = data[randomX][randomY]; data[randomX][randomY] = temp;
            }
        }



    }

    /**
     * 用于初始化窗体
     */
    public void initFrame(){
        setSize(514,595);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("石头迷阵v1.0");
        setAlwaysOnTop(true);
        setLocationRelativeTo(null);
        setLayout(null);
    }

    /**
     * 用于绘制游戏界面
     */
    public void painView(){
        for (int i=0;i<4;i++){
            for (int j=0;j<4;j++){
                System.out.println(data[i][j]);
                JLabel imageLabel = new JLabel(new ImageIcon("D:\\image\\"+data[i][j]+".png"));
                imageLabel.setBounds(50+100*j,90+100*i,100,100);
                getContentPane().add(imageLabel);
            }
        }

        JLabel background = new JLabel(new ImageIcon("D:\\image\\background.png"));
        background.setBounds(26,30,450,484);
        getContentPane().add(background);

        super.getContentPane().repaint();

    }
}

test类:

package StonePuzzie;

public class test {
    public static void main(String[] args) {
//        调用执行构造方法
//        相当于: MainFrame mainFrame =new MainFrame();
        new MainFrame();
    }
}

这样就完成第一步,初始化窗口展示:

在这里插入图片描述

2、添加移动石头业务模块:

使用键盘上下左右键进行对石头的移动,就需要使用接口KeyListener,对键盘进行监听,所有MainFrame类需要实现接口,即implements KeyListener。再重写接口中的keyPressed,监听键盘按下的事件。方法中添加move方法的代码,用于移动石块。

前提是需要在数据初始化时,找到黑方块。”0“编号的数组下标。再进行对0编号进行move操作:

寻找0编号数组下标:

      int row;        // 0号元素行坐标位置
    int column;     // 0号元素列坐标位置
    //        用于确定0格子的位置
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] == 0) {
                    row = i;
                    column = j;
                }
            }

编写move方法代码:

  private void move(int keyCode) {
        //左移动:
        if (keyCode == 37) {

            if (column == 3) {
                return;
            }

            // 空白块和右侧数据交换
            // data[row][column]  data[row][column+1]
            int temp = data[row][column];
            data[row][column] = data[row][column + 1];
            data[row][column + 1] = temp;
            column++;

//            上移动:
        } else if (keyCode == 38) {

            if (row == 3) {
                return;
            }

            // 空白块和下面的数据交换
            // data[row][column] data[row+1][column]
            int temp = data[row][column];
            data[row][column] = data[row + 1][column];
            data[row + 1][column] = temp;
            row++;

//            右移动
        } else if (keyCode == 39) {

            if (column == 0) {
                return;
            }

            // 空白块和左侧的数据交换
            // data[row][column] data[row][column-1]
            int temp = data[row][column];
            data[row][column] = data[row][column - 1];
            data[row][column - 1] = temp;
            column--;

//            下移动:
        } else if (keyCode == 40) {

            if (row == 0) {
                return;
            }

            // 空白块和上面的数据交换
            // data[row][column] data[row-1][column]
            int temp = data[row][column];
            data[row][column] = data[row - 1][column];
            data[row - 1][column] = temp;
            row--;
        }

重写监听键盘接口实现方法:

    @Override
    public void keyPressed(KeyEvent e) {
//        获得键盘按下的键的键值。
        int keyCode = e.getKeyCode();
        System.out.println("键值为:");
        System.out.println(keyCode);
//        传入move方法:
        move(keyCode);
//        执行一次移动后需要进行重新绘制游戏界面:
        painView();
    }

3、添加判断胜利模块:

该模块的添加,应该在展示用于绘制界面的方法painView()中,每次移动后需要重新绘制界面时,需要进行一个判断,,看现在的数组是否等于胜利的数组win:,输出胜利的图片:

判断是否胜利返回布尔值true or false:

int[][] win = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };
/**
     * 判断游戏是否胜利
     */
    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;

    }

中插入判断代码:

if(victory()){
            // 加载胜利图片资源, 添加到窗体中
            JLabel winLabel = new JLabel(new ImageIcon("D:\\image\\win.png"));
            winLabel.setBounds(124,230,266, 88);
            getContentPane().add(winLabel);
        }

4、添加记录步数和“重新游戏”模块:

该模块的记录步数,需要一开始定一个全局变量count,并且点击重新游戏的时候,count赋值为0,在move代码中,每进行一次移动,count++,最后在窗体展示的代码painView()中,创建一个窗体展示记录步数展示,再创建一个按钮,点击按钮后事件进行对游戏重新开始,重新初始化数组,count归为0。

记录步数:

int count;
JLabel scoreLabel = new JLabel("步数为:" + count);
        scoreLabel.setBounds(50,20,100,20);
        getContentPane().add(scoreLabel);

在这里插入图片描述

重新开始按钮:

     JButton btn = new JButton("重新游戏");
        btn.setBounds(350,20,100,20);
        getContentPane().add(btn);
//        取消按钮焦点。
        btn.setFocusable(false);
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                count =0;
                initData();
                painView();
            }
        });

在这里插入图片描述

5、添加作弊器,一键“胜利“:

添加作弊器,主要是在键盘按键监听事件中,添加一个if判断,如果自己设定的按键,(比如z,键值为:90),然后在move代码中写入对数据data重新赋值为胜利时的win数组一样的数据

 else if (keyCode == 90) {
            // 触发作弊器
            data = new int[][]{
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 0}
            };
        }

6、整体代码:

MainFrame类:

package com.itheima.stonepuzzle;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

public class MainFrame extends JFrame implements KeyListener {

    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 column;     // 0号元素列坐标位置
    int count;      // 统计步数
//构造方法::
    public MainFrame() {


        // 窗体对象.addKeyListener(KeyListener实现类对象);
        this.addKeyListener(this);
        // this : 当前类对象
        // 1) 窗体对象
        // 2) KeyListener实现类对象

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

    /**
     * 初始化数据 (打乱二维数组)
     */
    public void initData() {
        // 准备Random对象
        Random r = new Random();
        // 遍历二维数组, 获取到每一个元素
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                int randomX = r.nextInt(4);
                int randomY = r.nextInt(4);
                // data[i][j]
                // data[randomX][randomY]
                int temp = data[i][j];
                data[i][j] = data[randomX][randomY];
                data[randomX][randomY] = temp;
            }
        }
//        用于确定0格子的位置
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] == 0) {
                    row = i;
                    column = j;
                }
            }
        }

    }

    /**
     * 此方法用于初始化窗体
     */
    public void initFrame() {
        // 设置窗体大小
        setSize(514, 595);
        // 设置窗体关闭模式
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        // 设置窗体标题
        setTitle("石头迷阵单机版V1.0");
        // 设置窗体置顶
        setAlwaysOnTop(true);
        // 设置窗体居中
        setLocationRelativeTo(null);
        // 取消默认布局
        setLayout(null);
    }

    /**
     * 此方法用于绘制游戏界面
     */
    public void paintView() {


        getContentPane().removeAll();

        if(victory()){
            // 加载胜利图片资源, 添加到窗体中
            JLabel winLabel = new JLabel(new ImageIcon("D:\\image\\win.png"));
            winLabel.setBounds(124,230,266, 88);
            getContentPane().add(winLabel);
        }

        JButton btn = new JButton("重新游戏");
        btn.setBounds(350,20,100,20);
        getContentPane().add(btn);
        btn.setFocusable(false);
        btn.addActionListener(e -> {
            count = 0;
            initData();
            paintView();
        });

        JLabel scoreLabel = new JLabel("步数为:" + count);
        scoreLabel.setBounds(50,20,100,20);
        getContentPane().add(scoreLabel);

        for (int i = 0; i < 4; i++) {
            // i = 0 1 2 3
            for (int j = 0; j < 4; j++) {
                // j = 0 1 2 3
                JLabel imageLabel = new JLabel(new ImageIcon("D:\\image\\" + data[i][j] + ".png"));
                imageLabel.setBounds(50 + 100 * j, 90 + 100 * i, 100, 100);
                getContentPane().add(imageLabel);
            }
        }


        JLabel background = new JLabel(new ImageIcon("D:\\image\\background.png"));
        background.setBounds(26, 30, 450, 484);
        getContentPane().add(background);

        getContentPane().repaint();
    }

    /**
     * 判断游戏是否胜利
     */
    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;

    }


    /**
     * 此方法用于处理移动业务
     */
    private void move(int keyCode) {

        if(victory()){
            return;
        }
//左移动:
        if (keyCode == 37) {

            if (column == 3) {
                return;
            }

            // 空白块和右侧数据交换
            // data[row][column]  data[row][column+1]
            int temp = data[row][column];
            data[row][column] = data[row][column + 1];
            data[row][column + 1] = temp;
            column++;
            count++;
//            上移动:
        } else if (keyCode == 38) {

            if (row == 3) {
                return;
            }

            // 空白块和下面的数据交换
            // data[row][column] data[row+1][column]
            int temp = data[row][column];
            data[row][column] = data[row + 1][column];
            data[row + 1][column] = temp;
            row++;
            count++;
//            右移动
        } else if (keyCode == 39) {

            if (column == 0) {
                return;
            }

            // 空白块和左侧的数据交换
            // data[row][column] data[row][column-1]
            int temp = data[row][column];
            data[row][column] = data[row][column - 1];
            data[row][column - 1] = temp;
            column--;
            count++;
//            下移动:
        } else if (keyCode == 40) {

            if (row == 0) {
                return;
            }

            // 空白块和上面的数据交换
            // data[row][column] data[row-1][column]
            int temp = data[row][column];
            data[row][column] = data[row - 1][column];
            data[row - 1][column] = temp;
            row--;
            count++;
        } else if (keyCode == 90) {
            // 触发作弊器
            data = new int[][]{
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 0}
            };
        }


    }
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
//        System.out.println("键值:");
//        System.out.println(keyCode);
        move(keyCode);
        // 每一次移动之后, 都重新绘制游戏界面
        paintView();
    }

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

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
    // ----------------------------------------------------
}

test类运行。

最后:

创作分享不易,如果觉得对您有一定的帮助,请点个小小关注bo。

在这里插入图片描述

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葡萄成熟时_

谢谢您,祝您生活愉快,所想及得

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值