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

在这里插入图片描述

目录

  • 1、绘制界面
  • 2、打乱石头方块
  • 3、移动业务
  • 4、游戏判定胜利
  • 5、统计步数
  • 6、重新游戏
  • 7、完整代码:

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) {
    }
    //-------------------------------------
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

获取时间戳是使用System.currentTimeMillis()还是使用new Date().getTime()(阿里开发规范)?

1.阿里规范 在阿里的Java开发手册中强制要求使用System.currentTimeMillis() 2.为什么(源码详解) new Date().getTime()它实际上也是调用的System.currentTimeMillis()&#xff0c;源码分析。 这个fastTime是它的成员变量&#xff0c;在new Date()的时候就被赋值了。 扩展一…

计算机组成原理笔记-第3章 系统总线

第三章 系统总线 笔记PDF版本已上传至Github个人仓库&#xff1a;CourseNotes&#xff0c;欢迎fork和star&#xff0c;拥抱开源&#xff0c;一起完善。 该笔记是最初是没打算发网上的&#xff0c;所以很多地方都为了自我阅读方便&#xff0c;我理解了的地方就少有解释&#xf…

Android自定义View之不得不知道的文件attrs

其中demo_style如下:一般都是放的.9图片&#xff0c;为了方便就放个颜色了 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190820183209784.png?x-oss-processimage/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLm NzZG4ubmV0L3FxXzQyNzYxMz…

IDS使用规则

ids入侵检测系统 Snort(基于特征的入侵检测系统) 软硬件配套 snort官网链接&#xff1a;Snort - Network Intrusion Detection & Prevention System(https://www.snort.org) 环境&#xff1a;centos7,拖动需要开共享粘贴板和开双向 一、daq 1、预装dap所需程序 yum inst…

Unity 限时免费资源 - FANTASTIC万圣节资源包

Unity 资源 - FANTASTIC - Halloween Pack 万圣节包 前言资源包内容领取兑换码 前言 亲爱的 Unity 游戏开发者们&#xff0c;今天要给大家介绍一款限时免费的优质资源包 - FANTASTIC - Halloween Pack 万圣节资源包。 这个资源包为您的游戏创作带来了丰富的万圣节主题元素。其…

《STM32 HAL库》CAN通信系列函数详尽解析——HAL_CAN_Init()

食用指南&#xff1a;本文主要内容为梳理CAN初始化函数主要运行逻辑及重点功能实现代码的详尽解析。函数源码在文末&#xff0c;建议在阅读源码之后观看。 CAN相关寄存器图&#xff1a; 主要逻辑分析&#xff1a; 下面分点梳理函数的主要逻辑&#xff08;注意逻辑序号&#xf…

Python提取PDF文本和图片,以及提前PDF页面中指定矩形区域的文本

前言 从PDF中提取内容能帮助我们获取文件中的信息&#xff0c;以便进行进一步的分析和处理。此外&#xff0c;在遇到类似项目时&#xff0c;提取出来的文本或图片也能再次利用。要在Python中通过代码提取PDF文件中的文本和图片&#xff0c;可以使用 Spire.PDF for Python 这个…

为什么五笔没人用了?

五笔输入法现在较少人使用的原因主要有以下几点&#xff1a; 学习门槛高&#xff1a;五笔输入法的学习难度相对较大&#xff0c;需要掌握所有的字根&#xff0c;全面了解编码的规律&#xff0c;并学习每个字的拆字原则&#xff0c;这要求用户有相当高的耐心和时间去学习和练习…

openh264 帧级码率控制原理:RcCalculatePictureQp 函数

RcCalculatePictureQp 函数 函数功能 在码控中&#xff0c;当eSliceType为P_SLICE时 计算 P 帧的帧级量化参数QP 值。 函数原理过程 初始化各类变量&#xff1b;计算帧复杂度iFrameComplexity&#xff0c;如果iUsageType是SCREEN_CONTENT_REAL_TIME&#xff0c;重复赋值帧复…

MySQL【触发器、存储过程、函数、范式】

day53 MySQL 触发器 创建触发器&#xff1a;&#xff08;before &#xff1a; 前置触发器、after &#xff1a;后置触发器&#xff09; 语法&#xff1a; delimiter xx 指定分隔符xxcreate trigger 触发器名 [before | after] 触发事件 on 表名 for each row 执行语句begin…

maven:中央仓库验证方式改变:401 Content access is protected by token

前几天向maven中央仓库发布版本&#xff0c;执行上传命令mvn release:perform时报错了&#xff1a; [ERROR] Failed to execute goal org.sonatype.plugins:nexus-staging-maven-plugin:1.6.13:deploy (injected-nexus-deploy) on project xxxxx: Failed to deploy artifacts: …

智慧互联,Vatee万腾平台引领新潮流

在数字化、智能化的新时代&#xff0c;智慧互联正成为推动社会进步的重要力量。在这一潮流中&#xff0c;Vatee万腾平台凭借其卓越的技术实力和创新理念&#xff0c;正引领着新潮流&#xff0c;将智慧互联的理念融入生活的方方面面。 Vatee万腾平台是一个以大数据、云计算、人工…

C#利用SignalR实现通信事例Demo

1.服务端安装SignalR的Nuget包 dotnet add package Microsoft.AspNet.SignalR --version 2.4.3 2.接下来&#xff0c;创建一个ChatHub类&#xff0c;它是SignalR通信的核心&#xff1a; using Microsoft.AspNetCore.SignalR;public class ChatHub : Hub {public static Dict…

聊聊 C# dynamic 类型,并分享一个将 dynamic 类型变量转为其它类型的技巧和实例

前言 dynamic 是一种有别于传统变量类型的动态类型声明&#xff0c;刚开始接触可能在理解上会有些困难&#xff0c;可以简单地把它理解为一个盲盒&#xff0c;你可以任意猜测盒子有什么东西&#xff0c;并认为这些东西真正存在而进行处理&#xff0c;等到真正打开时&#xff0…

文章自动生成器,在线AI写作工具

随着人工智能AI技术的发展&#xff0c;AI技术被应用到越来越多的场景。对于需要创作内容的同学来说&#xff0c;AI写作-文章内容自动生成器是一个非常好的辅助工具。AI写作工具可以提升我们的创作效率&#xff0c;快速的生成文章&#xff0c;然后在根据需求进行调整修改即可。下…

语法制导的翻译和属性文法

属性的分类 1.综合属性 重写规则&#xff08;产生式&#xff09;左部符号的属性是综合属性。一个结点相应文法符号的属性值通过语法分析树中它的子节点的属性之值计算&#xff08;自底向上&#xff09; 2.继承属性 出现在重写规则右部的符号的属性。一个结点相应文法符号的属性…

概念描述——TCP/IP模型中的两个重要分界线

TCP/IP模型中的两个重要分界线 协议的层次概念包含了两个也许不太明显的分界线&#xff0c;一个是协议地址分界线&#xff0c;区分出高层与低层寻址操作&#xff1b;另一个是操作系统分界线&#xff0c;它把系统与应用程序区分开来。 高层协议地址界限 当我们看到TCP/P软件的…

没等来百度惊艳的All in AI,却等来了国产之光的盘古大模型 5.0

6月21日&#xff0c;华为开发者大会&#xff08;HDC 2024&#xff09;在广东东莞正式开幕。盘古大模型5.0的更新&#xff0c;也是此次HDC2024的另一项重头戏。在过去的一年中&#xff0c;盘古大模型正在疯狂向各行各业渗透。 此次&#xff0c;华为方面展示了他们在具身智能、医…

【面向对象】复习(二)

内存对齐 class A{ static int a; } int main(){ A obj; cout<<sizeof(obj); } 在你的代码中&#xff0c;class A 包含一个静态成员变量 a。静态成员变量不属于类的任何特定实例&#xff0c;而是属于整个类。因此&#xff0c;在计算类的实例大小时&#xff0c;静态…

C语言入门系列:指针入门(超详细)

文章目录 一&#xff0c;什么是指针1&#xff0c;内存2&#xff0c;指针是什么&#xff1f; 二&#xff0c;指针的声明1&#xff0c;声明指针类型变量2&#xff0c;二级指针 三&#xff0c;指针的计算1&#xff0c;两个指针运算符1.1 *运算符1.2 & 运算符1.3 &运算符与…