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

news2024/10/6 10:38:38

自学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。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169820.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【openGauss实战5】表管理及CURD

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

汽车网络技术概述

车辆总线是一个专门的内部通信网络&#xff0c;将车辆&#xff08;如汽车、公共汽车、火车、工业或农业车辆、船舶或飞机&#xff09;内的部件相互连接。在电子学中&#xff0c;总线只是一个将多个电气或电子设备连接在一起的设备。车辆控制的特殊要求&#xff0c;如保证信息传…

数据分析-深度学习 Pytorch Day7

图像识别&#xff1a;CIFAR10图形识别1.CIFAR10数据集共有60000张彩色图像&#xff0c;这些图像式32*32*3&#xff0c;分为10个类&#xff0c;每个类6000张2.这里面有50000张用于训练&#xff0c;构成5个训练批&#xff0c;每一批10000张图&#xff1b;另外10000张用于测试&…

vhdx中的win10进行大版本系统升级

文章目录前言普通的win10大版本iso升级方式vhdx中的win10大版本升级方式难点分析 - 无法在虚拟驱动器上安装windows解决方案 - HyperV升级vhdx win10过程效果图hyperV虚机创建mbr引导启动项hyperV虚机设置在hyperV中升级过程图问题集锦问题一&#xff1a;hyverV虚机中升级报错&…

力扣刷题记录——561. 数组拆分、566. 重塑矩阵、575. 分糖果

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《力扣刷题记录——561. 数组拆分、566. 重塑矩阵、575. 分…

IDEA远程调试

1 概述 原理&#xff1a;本机和远程主机的两个 VM 之间使用 Debug 协议通过 Socket 通信&#xff0c;传递调试指令和调试信息。 被调试程序的远程虚拟机&#xff1a;作为 Debug 服务端&#xff0c;监听 Debug 调试指令。jdwp是Java Debug Wire Protocol的缩写。 调试程序的本…

初识redis

1.初识Redis Redis是一种键值型的NoSql数据库&#xff0c;这里有两个关键字&#xff1a; 键值型 NoSql 其中键值型&#xff0c;是指Redis中存储的数据都是以key、value对的形式存储&#xff0c;而value的形式多种多样&#xff0c;可以是字符串、数值、甚至json&#xff1a;…

HTTPS一定可靠吗?

HTTPS一定可靠吗&#xff1f;中间人伪装服务器首先我们先看看客户端是如何验证证书的&#xff1f;数字证书签发和验证流程客户端校验服务端数字证书的过程如何出现中间人伪装服务器成服务器的情况&#xff1f;避免该情况中间人伪装服务器 客户端向服务端发起HTTPS建立连接请求时…

你知道吗?python lxml 库也能用于操作 svg 图片

在大多数场景中&#xff0c;我们都用 lxml 库解析网页源码&#xff0c;但你是否知道&#xff0c;lxml 库也是可以操作 svg 图片的。我们可以使用 lxml 中的 etree 模块来解析 SVG 文件&#xff0c;然后使用 SVG 中的各种元素和属性来进行操作。 python lxml 库操作 svg 图片lxm…

传输层协议:TCP协议(上)——协议结构、主要特点以及应用场景

简介 传输控制协议&#xff08;英语&#xff1a;Transmission Control Protocol&#xff0c;缩写&#xff1a;TCP&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议&#xff0c;由IETF的RFC 793定义。在简化的计算机网络OSI模型中&#xff0c;它完成第四层传…

xubuntu系统偶发自动登出

项目场景&#xff1a; 系统&#xff1a;xubuntu-16.04.3-desktop 问题描述 使用xubuntu系统期间&#xff0c;在root用户下进行相关开发&#xff0c;突然系统会回到普通用户登录界面&#xff0c;需要输入密码进入到普通用户下   它会终止所有打开的应用程序和进程&#xff0…

【Vue组件通信方式】

文章目录前言一、父子组件通信1、父传子①使用props接收父组件传递的属性② 使用$attrs接收父组件未在 props 和 emits 中定义的属性和事件③使用 $parent获取父组件的信息2、子传父① 使用 $emit传递信息给父组件② 使用$refs获取子组件的属性和事件二、自定义事件&#xff1a…

独家丨DeepMind科学家、AlphaTensor一作解读背后的故事与实现细节

一直以来&#xff0c;DeepMind的Alpha系列工作&#xff0c;AlphaGo、AlphaStar等致力于棋类和游戏应用中战胜人类&#xff0c;而两个月前发布的AlphaTensor则把目标指向了科学计算领域&#xff0c;意在为矩阵乘法等基本计算任务自动设计更高效的经典算法&#xff0c;这一工作一…

Burpsuite超详细安装教程(附安装包)

写在开头 Burp Suite 是用于攻击web 应用程序的集成平台&#xff0c;包含了许多工具。Burp Suite为这些工具设计了许多接口&#xff0c;以加快攻击应用程序的过程。所有工具都共享一个请求&#xff0c;并能处理对应的HTTP 消息、持久性、认证、代理、日志、警报。 接下来我来…

软件测试面试经 | 双非院校,从外包到外企涨薪85%,他的涨薪秘籍全公开

本文为霍格沃兹测试开发学社优秀学员跳槽笔记&#xff0c;测试开发进阶学习文末加群。 本身是一所不入流的院校毕业的一名建工类专业的瓜娃子&#xff0c;至今记得当初是因为找工作被培训公司忽悠才加入到这个行业的&#xff0c;抱着做着试试的想法这一干在深圳就是6年&#xf…

excel替换技巧:如何将手机号码的部分数字变成星号

每个销售员经常会接触大量客户&#xff0c;会用小本本记下众多客户的信息&#xff0c;而手机号码就是其中重要的一项。为了保护客户隐私&#xff0c;在公开的信息里销售员需要把客户手机号码的部分数字变成星号。比如说&#xff0c;把客户A的手机号码15867852976修改成158****2…

SpringMvc源码分析(三) 请求执行过程之获取MethodHandler

1.请求是如何关联到DispatcherServlet的 DispatcherServlet是Servlet的实现&#xff0c;遵循Servlet生命周期的规则。 Servlet的生命周期即其出生到死亡的过程中分别会调用Servlet里的以下方法&#xff1a; 加载和实例化&#xff1a;可以参考SpringMvc源码分析一 init方法…

【JavaEE】博客前端

目录 一、列表页 1.1导航条 1.2主题区域 1.2.1个人信息框 1.2.2 内容区 二、登录页 三、详情页 一、列表页 整体布局如下&#xff1a; 1.1导航条 导航条分为三块&#xff0c;整体都设置id为导航栏&#xff0c;然后左右分为导航栏左和导航栏右。左边靠左&#xff0c;右边靠…

计算机视觉Computer Vision课程学习笔记四之Region and Edge Descriptions

第四章讲了区域和边界的描述 包括最佳区域评估方法&#xff0c;多物体识别&#xff0c;标签算法&#xff0c;斑点标记 以及矩评估的方法和优劣 Region Description Simple measurements on binary images • Use for recognition, etc. • Generate region descriptions whic…

Win10+CMake+VS2017编译OpenCV4.5.5

第一步&#xff1a;准备工作1 下载opencv4.5.5下载OpenCV4.5.5&#xff0c;并解压到自己新建文件夹opencv下。2 下载opencv_contrib4.5.5下载opencv_contrib4.5.5&#xff0c;解压到上面的opencv文件夹中&#xff0c;并在opencv文件夹中新建一个build文件夹&#xff0c;用来存放…