Java实现推箱子小游戏(idea+mySQL)

就是我们学校实训有个推箱子的小游戏,一开始只是完成任务,然后……【想法越来越多,我的第一个小游戏就诞生了,虽然可能就我一个人玩了,但是很高兴能和你分享制作的过程!】
完整的白嫖代码以及资料可以通过下面的百度云连接获取
(大家可以根据源码和看文章中对各个板块的说明这样更加清晰一点)

链接:https://pan.baidu.com/s/18LGcssj8ms-A7WgPNH3bwQ 提取码:yncd
复制这段内容后打开百度网盘手机App,操作更方便哦

游戏部分功能及部分地图展示

java推箱子游戏 java推箱子小游戏_游戏

一、游戏设定

1.玩法

把箱子推到指定的地方,这里我把箱子替换成了礼物,需要把礼物搬运到指定的地点,就能进入下一关。

2.剧情

小熊要给小兔子过生日,在每一年都会准备不同的礼物,当所有礼物都送达的时候,小熊就会给小兔子送上这一年的生日祝福!小兔子也能按时长大一岁。

二、需求分析

1.用户登录界面

玩家凭借用户名和密码登录,没有账号时可以选择注册

java推箱子游戏 java推箱子小游戏_mysql_02

2.游戏界面

java推箱子游戏 java推箱子小游戏_游戏_03

(1)窗体标题栏

java推箱子游戏 java推箱子小游戏_java推箱子游戏_04


玩家登入成功后就会在窗体的标题栏上显示用户昵称

(2)窗体菜单栏

java推箱子游戏 java推箱子小游戏_swing_05


玩家可以在通过菜单栏的点击实现相应的功能

(3)主要按钮

java推箱子游戏 java推箱子小游戏_swing_06


java推箱子游戏 java推箱子小游戏_游戏_07

玩家可以点击按钮实现相应的功能

(4)主面版

java推箱子游戏 java推箱子小游戏_swing_08


玩家可以通过键盘,实现小熊位置的移动,箱子的推动,所有箱子推到指定位置(就是小熊爪印的时候)就会自动进入下一关,在右侧的版面,有关卡的提示功能,记录步骤,送达礼物,用时,实现所有玩家的排行(前三名),并在右下角有当前的时间显示。

三、数据库设计

1.用MySQL设计存储玩家信息的表

这里我们用到的是mySQL

创建数据库-> mygame

创建数据表-> user

java推箱子游戏 java推箱子小游戏_java_09

2.为了后续方便操作,我们可以使用idea的Database功能

java推箱子游戏 java推箱子小游戏_swing_10


填写用户名和密码一般就可以连接成功了,但是MySQL(8.0)好像是要配置时区的

四、需要提前创建的一些接口类

工程总览

java推箱子游戏 java推箱子小游戏_mysql_11

1.class GameUtil【负责实现图面的读取】

package yuixiangzi;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

public class GameUtil {
    // 工具类最好将构造器私有化。
    private GameUtil() {

    }

    public static Image getImage(String path) {
        BufferedImage bi = null;
        try {
            URL u = GameUtil.class.getClassLoader().getResource(path);
            bi = ImageIO.read(GameUtil.class.getResourceAsStream(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bi;
    }
}

2.class SetImage【这是我对文件夹中的图片进行的处理】

package yuixiangzi;

import java.awt.*;

public class SetImage {
    private SetImage() {

    }
    public static Image[] GetImage(int year) {
        Image img1 = GameUtil.getImage("/pic/1.png");
        Image img2 = GameUtil.getImage("/pic/2.png");
        Image img3 = GameUtil.getImage("/pic/3.png");
        Image img4 = GameUtil.getImage("/pic/4.png");
        Image img5 = GameUtil.getImage("/pic/5.png");
        Image img6 = GameUtil.getImage("/pic/6.png");
        Image img7 = GameUtil.getImage("/pic/7.png");
        Image img8 = GameUtil.getImage("/pic/8.png");
        Image img9 = GameUtil.getImage("/pic/9.png");
        Image img10 = GameUtil.getImage("/pic/10.png");
        Image img11 = GameUtil.getImage("/pic/11.png");
        Image img12 = GameUtil.getImage("/pic/12.png");
        Image img13= GameUtil.getImage("/pic/13.png");
        Image img14 = GameUtil.getImage("/pic/14.png");
        Image img15 = GameUtil.getImage("/pic/001.png");
        Image img16 = GameUtil.getImage("/pic/002.png");
        Image img17 = GameUtil.getImage("/pic/003.png");
        Image img18 = GameUtil.getImage("/pic/004.png");
        Image img19 = GameUtil.getImage("/pic/005.png");
        Image img20 = GameUtil.getImage("/pic/006.png");
        Image img21 = GameUtil.getImage("/pic/007.png");
        Image img22 = GameUtil.getImage("/pic/008.png");
        Image img23 = GameUtil.getImage("/pic/009.png");
        Image img24 = GameUtil.getImage("/pic/010.png");
        Image img25 = GameUtil.getImage("/pic/011.png");
        Image img26 = GameUtil.getImage("/pic/012.png");
        Image img27 = GameUtil.getImage("/pic/013.png");
        Image img28 = GameUtil.getImage("/pic/014.png");
        Image img29 = GameUtil.getImage("/pic/015.png");
        Image img30 = GameUtil.getImage("/pic/016.png");
        Image img31 = GameUtil.getImage("/pic/017.png");
        Image img32 = GameUtil.getImage("/pic/018.png");
        Image img33 = GameUtil.getImage("/pic/019.png");
        Image img34 = GameUtil.getImage("/pic/020.png");
        Image img35 = GameUtil.getImage("/pic/021.png");
        Image img36 = GameUtil.getImage("/pic/022.png");
        Image img37 = GameUtil.getImage("/pic/023.png");
        Image img38 = GameUtil.getImage("/pic/024.png");
        Image img39 = GameUtil.getImage("/pic/025.png");
        Image img40 = GameUtil.getImage("/pic/026.png");
        Image img41 = GameUtil.getImage("/pic/027.png");
        Image img42 = GameUtil.getImage("/pic/028.png");
        Image img43 = GameUtil.getImage("/pic/029.png");
        Image img44 = GameUtil.getImage("/pic/030.png");
        Image img45 = GameUtil.getImage("/pic/031.png");
        Image img46 = GameUtil.getImage("/pic/032.png");
        Image img47 = GameUtil.getImage("/pic/033.png");
        Image img48 = GameUtil.getImage("/pic/034.png");
        Image img49 = GameUtil.getImage("/pic/035.png");
        Image img50 = GameUtil.getImage("/pic/036.png");
        Image img51 = GameUtil.getImage("/pic/037.png");
        Image img52 = GameUtil.getImage("/pic/038.png");
        Image img53 = GameUtil.getImage("/pic/039.png");
        Image img54 = GameUtil.getImage("/pic/040.png");
        Image img55 = GameUtil.getImage("/pic/041.png");
        Image img56 = GameUtil.getImage("/pic/042.png");
        Image img57 = GameUtil.getImage("/pic/043.png");
        Image img58 = GameUtil.getImage("/pic/044.png");
        Image img59 = GameUtil.getImage("/pic/045.png");
        Image img60 = GameUtil.getImage("/pic/046.png");
        Image img61 = GameUtil.getImage("/pic/047.png");
        Image img62 = GameUtil.getImage("/pic/048.png");
        Image img63 = GameUtil.getImage("/pic/049.png");
        Image img64 = GameUtil.getImage("/pic/050.png");
        Image img65 = GameUtil.getImage("/pic/051.png");
        Image img66 = GameUtil.getImage("/pic/052.png");
        Image img67 = GameUtil.getImage("/pic/053.png");
        Image img68 = GameUtil.getImage("/pic/054.png");
        Image img69 = GameUtil.getImage("/pic/055.png");
        Image img70 = GameUtil.getImage("/pic/056.png");
        Image img71 = GameUtil.getImage("/pic/057.png");
        Image img72 = GameUtil.getImage("/pic/058.png");
        Image img73 = GameUtil.getImage("/pic/059.png");
        Image img74 = GameUtil.getImage("/pic/060.png");
        Image img75 = GameUtil.getImage("/pic/061.png");
        Image img76 = GameUtil.getImage("/pic/062.png");
        Image img77 = GameUtil.getImage("/pic/063.png");
        Image img78 = GameUtil.getImage("/pic/064.png");
        Image img79 = GameUtil.getImage("/pic/065.png");
        Image img80 = GameUtil.getImage("/pic/066.png");
        Image img81 = GameUtil.getImage("/pic/067.png");
        Image img82 = GameUtil.getImage("/pic/068.png");
        Image img83 = GameUtil.getImage("/pic/069.png");
        //imag40 6 7 3不变其他自己配置 00命名的记得加14
        Image[] maping = new Image[10];
        if(year%7==1){
              maping = new Image[]{
                      img34, img36, img40, img6, img7, img3, img3, img3, img3, img5,
              };
        }
        else if(year%7==2){
            maping = new Image[]{
                    img35, img64, img40, img6, img7, img3, img3, img3, img3, img60,
            };
        }
        else if(year%7==3){
            maping = new Image[]{
                    img68, img71, img40, img6, img7, img3, img3, img3, img3, img69,
            };
        }
        else if(year%7==4){
            maping = new Image[]{
                    img41, img50, img40, img49, img58,img37, img37, img37, img37, img42,
            };
        }
        else if(year%7==5){
            maping = new Image[]{
                    img13, img23, img40, img6, img7,img3, img3, img3, img3, img66,
            };
        }
        else if(year%7==6){
            maping = new Image[]{
                     img46,img56, img40, img6, img7,img3, img3, img3, img3, img65,
            };
        }
        else{
            maping = new Image[]{
                    img54,img42, img40, img6, img7,img3, img3, img3, img3, img2,
            };
        }
        return maping;
    }
}

3.class JDBCUtils【数据库连接工具类】

package yuixiangzi;

import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

//JDBC工具了
public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    static {
        try {
            Properties pro=new Properties();
            pro.load(new FileReader("src\\jdbc.properties"));

            url = pro.getProperty("url");
            user=pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");

            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException{
        return DriverManager.getConnection(url,user,password);
    }

    public static void close(Statement stmt,Connection conn){
        if(stmt !=null){
            try{
                stmt.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        if(conn !=null){
            try{
                conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
    public static void close(ResultSet rs,Statement stmt, Connection conn){
        if(rs !=null){
            try{
                rs.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        if(stmt !=null){
            try{
                stmt.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        if(conn !=null){
            try{
                conn.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    }
}

4.jdbc.properties【方便更改数据库】

java推箱子游戏 java推箱子小游戏_java推箱子游戏_12


特别特别要注意,不要多打空格!!!(当初连数据库的时候就是因为这里多打了空格找了好久的原因QVQ)

url=jdbc:mysql:///mygame
user=root
password=root
driver=com.mysql.cj.jdbc.Driver

五、登入窗口实现

1.界面外观设计

我就是喜欢这样可可爱爱(花里胡哨)的设计!谁说程序员就不可以粉粉嫩嫩的嘛!

class MyGameLogin extends JFrame {

    String username = null;
    String password = null;

    public MyGameLogin() {
        super("时光登入口");
        String path = "/pic/10.png";
        //设置窗体图标
        try {
            Image image = ImageIO.read(getClass().getResource(path));
            setIconImage(image);
        } catch (IOException e) {
            e.printStackTrace();
        }
        setSize(400, 400);


        Container C = getContentPane();
        C.setLayout(null);
        C.setBackground(new Color(255, 228, 196));

        JLabel lblTitle = new JLabel("时光登入口");
        lblTitle.setForeground(new Color(255, 140, 0));
        lblTitle.setFont(new Font("幼圆", Font.BOLD, 35));
        lblTitle.setBounds(100, 35, 200, 35);
        add(lblTitle);

        JLabel lblLogin = new JLabel("玩家名:");
        lblLogin.setForeground(new Color(244, 164, 96));
        lblLogin.setFont(new Font("幼圆", Font.BOLD, 20));
        lblLogin.setBounds(70, 160, 100, 35);
        add(lblLogin);

        JLabel lblLogin1 = new JLabel("密码:");
        lblLogin1.setForeground(new Color(244, 164, 96));
        lblLogin1.setFont(new Font("幼圆", Font.BOLD, 20));
        lblLogin1.setBounds(70, 220, 100, 35);
        add(lblLogin1);

        JButton btnLogin;
        btnLogin = new JButton("注册");
        btnLogin.setForeground(new Color(255, 127, 80));
        btnLogin.setBackground(new Color(255, 222, 173));
        btnLogin.setBounds(230, 270, 80, 30);
        C.add(btnLogin);

        JPasswordField passWord = new JPasswordField();
        passWord.setForeground(new Color(255, 140, 0));
        passWord.setBounds(170, 220, 140, 35);
        C.add(passWord);

        JTextField userName = new JTextField();
        userName.setForeground(new Color(255, 140, 0));
        userName.setBounds(170, 160, 140, 35);
        C.add(userName);

        JButton btnLogin1;
        btnLogin1 = new JButton("登入");
        btnLogin1.setForeground(new Color(255, 127, 80));
        btnLogin1.setBackground(new Color(255, 222, 173));
        btnLogin1.setBounds(100, 270, 80, 30);
        C.add(btnLogin1);

        setVisible(true);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


    Image imagetx = GameUtil.getImage("/pic/1.png");
    Image imagexx = GameUtil.getImage("/pic/3.png");
    Image imageLove = GameUtil.getImage("/pic/13.png");
    Image imageFlower1 = GameUtil.getImage("/pic/003.png");
    Image imageFlower2 = GameUtil.getImage("/pic/009.png");
    Image imageFlower3 = GameUtil.getImage("/pic/005.png");
    Image imageFlower4 = GameUtil.getImage("/pic/012.png");

    public void paint(Graphics g) {
        super.paint(g);
        g.drawImage(imageFlower1, 90, 150, null);
        g.drawImage(imageFlower3, 120, 150, null);
        g.drawImage(imagetx, 150, 150, null);
        g.drawImage(imageLove, 180, 150, null);
        g.drawImage(imagexx, 210, 150, null);
        g.drawImage(imageFlower2, 240, 150, null);
        g.drawImage(imageFlower4, 270, 150, null);
    }
}

2.登录功能实现

(1)登录按钮监听

按下登录按钮后,开始判断用户名和密码是否不为空,如果不为空,则进行查询语句的判断。

btnLogin1.addActionListener(new AbstractAction() {
            @Override
            /*[为什么这里不能判断是否为空]
                如果这个遗留问题不解决,那么后面的注册插入数据库的操作有没有办法执行*/
            public void actionPerformed(ActionEvent e) {
                username = userName.getText();
                password = new String(passWord.getPassword());
                System.out.println("test:" + username);
                System.out.println("test:" + password);
                if (StringUtils.isNullOrEmpty(username)) {
                    JOptionPane.showMessageDialog(null, "小兔子:真是的!你连名字都不告诉我");
                }
                if (StringUtils.isNullOrEmpty(password)) {
                    JOptionPane.showMessageDialog(null, "咦?你忘记了我们之间的暗号!不是不是小兔子乖乖,把门开开啦!");
                }
                if (!StringUtils.isNullOrEmpty(username) && !StringUtils.isNullOrEmpty(password)) {
                    //【这里执行查找语句】
                    if (login()) {
                        JOptionPane.showMessageDialog(null, "小兔子:你好!" + username + "又见面了!");
                        dispose();
                        long startTime =  System.currentTimeMillis();
                        System.out.println(startTime);
                        int[] result= null;
                        result=select(username);
                        select(username);
                        new myGame(startTime,username,result[0],result[1],result[2]);

                    } else {
                        JOptionPane.showMessageDialog(null, "小兔子:我好像不认识你哦!");
                    }
                }

            }
        });

(2)查询数据库判断该用户密码是否正确

public boolean login() {

        if (username == null || password == null) {
            return false;
        }
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            String sql = "select* from user where id= ? and password = ? ";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1,username);
            pstmt.setString(2,password);
            rs = pstmt.executeQuery();
            return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(rs, pstmt, conn);
        }
        return false;
    }

(3)用户登录后查询保存的游戏信息

public int[] select(String username){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int[] result= null;
        try {
            int grift,level,step;
            conn = JDBCUtils.getConnection();
            String sql = "select grift,lever,step from user where id= ? ";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1,username);
            rs = pstmt.executeQuery();
            result=new int[3];
            while (rs.next()){
                grift=rs.getInt("grift");
                level=rs.getInt("lever");
                step=rs.getInt("step");
                result[0]=grift;
                result[1]=level;
                result[2]=step;
            }
            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(rs, pstmt, conn);
        }
        return result;
    }

3.注册功能的实现

(1)注册按钮的监听

btnLogin.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                username = userName.getText();
                password = new String(passWord.getPassword());
                //[这里执行插入语句]
                if (!StringUtils.isNullOrEmpty(username) && !StringUtils.isNullOrEmpty(password)) {
                    JOptionPane.showMessageDialog(null, "小兔子:你好!" + username + "很高兴和你做朋友");
                    insert(username,password);
                    dispose();
                    long startTime =  System.currentTimeMillis();
                    System.out.println(startTime);
                    new myGame(startTime,username,0,1,0);
                }
                else {
                    JOptionPane.showMessageDialog(null, "小兔子:我好像不认识你哦!");
                }
            }
        });

(2)插入用户信息功能的实现

//这是插入语句
    public void insert(String userName,String passWord) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtils.getConnection();
            String sql = "insert into user values (?,?,0,1,0)";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, userName);
            pstmt.setString(2, passWord);
            int count = pstmt.executeUpdate();
            if (count > 0) {
                System.out.println("注册成功");
            } else {
                System.out.println("插入失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(pstmt, conn);
        }
    }

六、游戏版面的实现

1.实现游戏地图的导入及图形的显示

(1)游戏地图的读取

java推箱子游戏 java推箱子小游戏_游戏_13

每一关有又相应的由int map[20][20]的二维数组组成,我们只需要读取响应的数字,然后放置相应名字的图片在面板上就好了。

class ReadMap{
    private int map[][];
    //人物位置
    private int mx,my;
    //游戏关卡编号
    private int level;
    public ReadMap(int level){
        this.level=level;
        //文件路径
        String sfilename ="src\\maps\\"+level+".map";
        String content="";
        //文件字符流读取文件src\maps\0.map
        try{
            FileReader fr = new FileReader(sfilename);
            BufferedReader br = new BufferedReader(fr);
            String temp = "";
            //一行一行地读取文件,如果读到文件的末尾返回null
            while ((temp = br.readLine())!=null){
                content += temp;
            }
            //转化成字节数组
            byte b[] = content.getBytes();
            map = new int[20][20];
            int c =0;
            for(int i=0;i<20;i++){
                for(int j=0;j<20;j++){
                    map[i][j]=b[c]-48;
                    c++;
                    //返回人物的位置
                    if(map[i][j]==5){
                        mx=i;
                        my=j;
                    }
                }
            }
        }
        catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public  int[][] getMap(){
        return map;
    }

    public int getMx() {
        return mx;
    }

    public int getMy() {
        return my;
    }
}

2.游戏显示界面实现

(1)设计总的组件

//设置按钮
    JButton btnBack, btnNext, btnPrev, btnSelect, btnReset,
    //撤销一步,下一关,上一关,选择关卡,重新游戏
    btnMusic,//选择音乐
            btnLook;//查看当前排名
    JComboBox cbMusic;//下拉链表框,选择音乐
    JMenuBar menuBar;//菜单条
    JMenu menuOption, mnuSet, mnuHelp;
    //菜单条选项,关卡选择,音乐设置,帮助
    JMenuItem miReset, miPrev, miNext, miSelect, miExit, miBack;
    JMenuItem miMusic1, miMusic2;
    //帮助信息
    JMenuItem miHelp;
    //只有50关
    //定义一个数组存放音乐
    //创建MyPanel类
    MyPanel mainPanel;

(2)设计窗体

//设置窗体图标
        try {
            Image image = ImageIO.read(this.getClass().getResource(path));
            this.setIconImage(image);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Color bgColor = new Color(230, 230, 250);
        
        //设置窗体大小
        setSize(800, 840);

		//设置窗体颜色
        Container C = getContentPane();
        C.setLayout(null);
        C.setBackground(new Color(255, 240, 245));
        
        //将标题设置
        JLabel lblTitle = new JLabel("Happy Birthday !", JLabel.CENTER);
        lblTitle.setForeground(new Color(205, 92, 92));
        lblTitle.setFont(new Font("幼圆", Font.BOLD, 30));
        lblTitle.setBounds(100, 20, 500, 30);
        add(lblTitle);
		
		//设置主面板大小和背景颜色
        mainPanel = new MyPanel();
        mainPanel.setBounds(10, 90, 760, 600);
        mainPanel.setBackground(bgColor);
        C.add(mainPanel);
        createButton(C);
		
		//设置窗体可见
        setVisible(true);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

(3)设计按钮、音乐下拉选择框和下方标签

//创建按钮函数
    public void createButton(Container C) {
        //设置显示文字
        btnReset = new JButton("重新游戏");
        btnBack = new JButton("赖皮一下");
        btnNext = new JButton("跳过这关");
        btnPrev = new JButton("回溯一关");
        btnLook = new JButton("保存当前进度");
        btnSelect = new JButton("选择关卡");
        btnMusic = new JButton("关闭音乐");
        cbMusic = new JComboBox(sMusic);

        //设置按钮监听
        btnBack.addActionListener(this);
        btnMusic.addActionListener(this);
        btnNext.addActionListener(this);
        btnPrev.addActionListener(this);
        btnBack.addActionListener(this);
        btnLook.addActionListener(this);
        btnReset.addActionListener(this);
        btnSelect.addActionListener(this);
        //设置绝对位置
        btnReset.setBounds(10, 50, 95, 30);
        btnMusic.setBounds(110, 50, 95, 30);
        btnSelect.setBounds(210, 50, 95, 30);
        btnBack.setBounds(310, 50, 95, 30);
        btnPrev.setBounds(410, 50, 95, 30);
        btnNext.setBounds(510, 50, 95, 30);
        btnLook.setBounds(610, 50, 160, 30);
        btnReset.setBackground(new Color(255, 174, 185));
        btnMusic.setBackground(new Color(255, 174, 185));
        btnSelect.setBackground(new Color(255, 174, 185));
        btnBack.setBackground(new Color(255, 174, 185));
        btnPrev.setBackground(new Color(255, 174, 185));
        btnNext.setBackground(new Color(255, 174, 185));
        btnLook.setBackground(new Color(255, 174, 185));
        cbMusic.addItemListener(this);
        C.add(btnReset);
        C.add(btnMusic);
        C.add(btnSelect);
        C.add(btnLook);
        C.add(btnPrev);
        C.add(btnNext);
        C.add(btnBack);
        JLabel lblMusic = new JLabel("选择音乐");
        lblMusic.setBounds(610, 700, 160, 30);
        JLabel lblText1 = new JLabel("小熊:今天是小兔子的生日,我要赶紧把礼物给她送过去!");
        lblText1.setForeground(new Color(205, 92, 92));
        lblText1.setBounds(10, 700, 460, 30);
        C.add(lblText1);
        JLabel lblText2 = new JLabel("小熊:你问我是什么礼物?这是秘密!是小兔子喜欢的……");
        lblText2.setForeground(new Color(205, 92, 92));
        lblText2.setBounds(10, 730, 460, 30);
        C.add(lblText2);
        C.add(lblMusic);
        cbMusic.setBounds(610, 730, 160, 30);
        C.add(cbMusic);
    }

(4)设计菜单选项

public void createMenus() {
        //选项子菜单
        menuOption = new JMenu("选项(O)");
        menuOption.setMnemonic('O');//设置热键
        miReset = new JMenuItem("重置");
        miPrev = new JMenuItem("上一关");
        miNext = new JMenuItem("下一关");
        miSelect = new JMenuItem("选择");
        miExit = new JMenuItem("退出");
        miBack = new JMenuItem("撤销一步");
        menuOption.add(miReset);
        menuOption.add(miPrev);
        menuOption.add(miNext);
        menuOption.add(miSelect);
        menuOption.add(miBack);
        menuOption.addSeparator();//添加分隔条
        menuOption.add(miExit);

        //音乐子菜单
        mnuSet = new JMenu("设置(S)");
        mnuSet.setMnemonic('S');//设置热键
        miMusic1 = new JMenuItem(sMusic[0]);
        miMusic2 = new JMenuItem(sMusic[1]);
        ButtonGroup bg = new ButtonGroup();
        bg.add(miMusic1);
        bg.add(miMusic2);
        //帮助子菜单
        //默认选第一首
        setMenuState(0);
        mnuSet.add(miMusic1);
        mnuSet.add(miMusic2);
        mnuHelp = new JMenu("帮助(H)");
        mnuHelp.setMnemonic('H');
        miHelp = new JMenuItem("关于我们……");
        mnuHelp.add(miHelp);

        //监听
        miReset.addActionListener(this);
        miPrev.addActionListener(this);
        miNext.addActionListener(this);
        miBack.addActionListener(this);
        miSelect.addActionListener(this);
        miExit.addActionListener(this);
        miMusic1.addActionListener(this);
        miMusic2.addActionListener(this);
        miHelp.addActionListener(this);

        menuBar = new JMenuBar();
        menuBar.add(menuOption);
        menuBar.add(mnuSet);
        menuBar.add(mnuHelp);
        setJMenuBar(menuBar);
    }

(5)一些面板显示文字以及图片的实现

public void paint(Graphics g) {
            Image[] maping = SetImage.GetImage(level);
            super.paint(g);
            for (int i = 0; i < 20; i++) {
                for (int j = 0; j < 20; j++) {
                    g.drawImage(maping[tempmap[j][i]], i * 30, j * 30, null);
                }
            }
            g.drawImage(img11, 580, 30, null);
            g.drawImage(imagetx, 620, 550, null);
            g.drawImage(imagetx, 650, 550, null);
            g.drawImage(imagetx, 680, 550, null);
            g.drawImage(imagetx, 710, 550, null);
            g.drawImage(imageff, 595, 280, null);
            g.drawImage(imageff, 625, 280, null);
            g.drawImage(imageff, 700, 280, null);
            g.drawImage(imageff, 730, 280, null);
            g.setColor(new Color(233,150,122));
            g.setFont(new Font("幼圆", Font.BOLD, 20));
            g.drawString("小兔几" + level + "岁啦", 625, 30);
            nowlever=level;
            g.setColor(new Color(250,128,114));
            g.setFont(new Font("幼圆", Font.BOLD, 14));
            g.drawString("小熊熊在努力派送礼物", 605, 220);
            g.setColor(new Color(255,160,122));
            g.drawString("已经走了:" +nowstep + "步啦", 605, 240);

            g.setFont(new Font("幼圆", Font.BOLD, 16));
            g.setColor(new Color(205,92,92));
            g.drawString("排行榜", 655, 300);

            g.setFont(new Font("幼圆", Font.BOLD, 14));
            g.setColor(new Color(255,99,71));
            //[排行榜实现 6.22]要有查询操作 返回一个字符数组(排序)
//            g.drawString("第一名:"+id1+" "+"礼物:"+lw1+"步骤"+bz1);
            order();
            for(int i=0;i<sites.size();i++){
                g.drawString(sites.get(i),605,330+i*30);
            }
            sites.clear();

            g.setFont(new Font("幼圆", Font.BOLD, 14));
            g.setColor(new Color(255,165,0));
            g.drawString("已经送去:" + nowgrift + "礼物", 605, 260);
            long usedTimem = (endTime-startTime)/60000;
            long usedTimes =(endTime-startTime)%60000/1000;
            Date date = new Date();
            g.setColor(new Color(255,140,0));
            if(usedTimem>=0||usedTimes>=0)
            g.drawString("用时:" +usedTimem+ "分钟"+usedTimes+"秒", 605, 280);
            g.drawString(date.toString(), 600, 590);

        }

(6)关于版面中的order函数实现排行榜功能

//实现排行榜功能取前三名
        public void order(){
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "select grift,step,id from user order by grift desc,step asc limit 3 ";
                pstmt = conn.prepareStatement(sql);
                rs = pstmt.executeQuery();
                String s="";
                int fc=1;
                while(rs.next()){
                    s="第"+fc+"名:"+rs.getNString("id");
                    sites.add(s);
                    s="礼物:"+rs.getInt("grift")+" "
                            +"步骤"+rs.getInt("step");
                    sites.add(s);
                    s="";
                    fc++;
                }
                System.out.println(sites);
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.close(rs, pstmt, conn);
            }
        }

3.完善具体的功能

在之前的代码中已经完善了监听

(1)帮助功能的实现

if (e.getSource() == miHelp) {
            String str = "游戏简介:快帮小熊把礼物送到指定的位置吧\n";
            str += "版本信息:lcy制作,希望每一个小朋友都可以收到生日祝福!\n";
            JOptionPane.showMessageDialog(this, str, "帮助", JOptionPane.INFORMATION_MESSAGE);
        }

(2)退出功能的实现

else if (e.getSource() == miExit) {
            System.exit(0);
        }

关于setLevel()函数实现关卡

//设置关卡
        public void setLevel(int level) {
            if (level == 0) {
                this.level = 1;
            } else if (level == 50) {
                this.level = 50;
            } else if (level > 1) {//选择关卡
                this.level = level;
            } else {
                this.level = level + this.level;
            }
            //要在关卡范围之内
            if (this.level <= 0) {
                this.level = 1;
            } else if (this.level >= 50) {
                this.level = 50;
            }
            readFile(this.level);
            //清空
            step.clear();
            //设置焦点
            requestFocus();
        }

        public void setLevel() {
            readFile(this.level);
            //清空上一关保存在堆栈中的所有步骤
            step.clear();
            //设置焦点
            requestFocus();
        }

(3)下一关功能的实现

else if (e.getSource() == btnNext || e.getSource() == miNext) {
            mainPanel.setLevel(1);
        }

(4)上一关功能的实现

else if (e.getSource() == btnPrev || e.getSource() == miPrev) {
            mainPanel.setLevel(-1);
        }

(5)输入数字实现关卡跳转

else if (e.getSource() == btnSelect || e.getSource() == miSelect) {
            String slevel = JOptionPane.showInputDialog(this, "请输入你想祝福的年龄(1~50)", "时光直通车", JOptionPane.OK_CANCEL_OPTION);
            if (slevel != null) {
                try {
                    int level = Integer.parseInt(slevel);
                    if (level <= 0 || level >= 50) {
                        JOptionPane.showMessageDialog(this, "小兔子说:要输入1~50之间的数字");
                        return;
                    }
                    System.out.println("test:" + level);
                    mainPanel.setLevel(level);
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(this, "哎呀!是数字,请输入1~50之间的数字");
                    return;
                }
            }
        }

关于goBack()函数实现撤退一步拿向左退一步举例

我们需要用一个栈存储每一步(上下左右)每一步的两种情况(推到了箱子,没有推到箱子)

public void goBack() {
            //判断堆栈是否为空
            if (step.isEmpty()) {
                JOptionPane.showMessageDialog(null, "小熊已经回到出发点了!");
                return;
            }
            //1没有退箱子 11推了箱子
            int n = step.pop();//取出栈顶元素
            switch (n) {
                case 1:
                case 11:
                    backLeft(n);
            }
            requestFocus();
        }

当我们每次从栈中取出上一步的时候就要开始进行判断
1.如果上一步没有推箱子,原来人的位置就会变成空地
2.如果上一步推了箱子,那么原来人的位置就会变成箱子,而箱子的位置就会变成空地

public void backLeft(int step) {
            if (step == 1) { //没有推箱子
                tempmap[mx][my + 1] = 6;
                //原来站人的地方,现在变成草地
                if (map[mx][my] == 4 || map[mx][my] == 9)
                    tempmap[mx][my] = 4;
                else
                    tempmap[mx][my] = 2;
                my++;
            } else {//推了箱子
                tempmap[mx][my + 1] = 6;
                //原来站人的地方,现在放箱子
                if (map[mx][my] == 4 || map[mx][my] == 9) {
                    tempmap[mx][my] = 9;
                } else {
                    tempmap[mx][my] = 3;
                }
                //原来放箱子的地方,现在变成空地
                if (map[mx][my - 1] == 4 || map[mx][my - 1] == 9) {
                    tempmap[mx][my - 1] = 4;
                } else {
                    tempmap[mx][my - 1] = 2;
                }
                my++;
            }
            //重画界面
            repaint();
        }

(6)实现赖皮一步的功能

else if (e.getSource() == btnBack || e.getSource() == miBack) {
            mainPanel.goBack();
            mainPanel.requestFocus();
        }

关于sound函数实现音乐的控制

读取音乐文件,注意如果你想要自己喜欢的音乐请使用mid格式的音乐!

class Sound {

    String path = new String("src\\music\\");
    //默认背景音乐
    String file = new String("1.mid");
    Sequence seq;
    Sequencer midi;
    //判断是否在播放音乐
    boolean sign;
    public Sound() {
        loadSound();
    }
    //播放背景音乐的函数
    void loadSound() {
        try {
            seq = MidiSystem.getSequence(new File(path + file));
            midi = MidiSystem.getSequencer();
            midi.open();
            midi.setSequence(seq);
            midi.start();
            midi.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
        }
        catch ( Exception ex ) {
            ex.printStackTrace();
        }
        sign = true;
    }
    void mystop() {
        midi.stop();
        midi.close();
        sign = false;
    }
    //判断是否在播放背景音乐
    boolean isplay() {
        return sign;
    }
    //设置在下拉框中选择的背景音乐文件名称
    void setMusic(String e) {
        file = e;
    }
}

(7)实现音乐的开关功能

else if (e.getSource() == btnMusic) {
            String title = btnMusic.getText();
            if (title.equals("关闭音乐")) {
                if (sound.isplay()) {
                    sound.mystop();
                }
                //设置按钮标题
                btnMusic.setText("打开音乐");
            } else {
                btnMusic.setText("关闭音乐");
                sound.loadSound();
            }
        }

(8)实现音乐的选择功能

else if (e.getSource() == miMusic1) {
            cbMusic.setSelectedIndex(0);
        } 
        else if (e.getSource() == miMusic2) {
            cbMusic.setSelectedIndex(1);
        }

(9)实现重新选择功能

else if (e.getSource() == btnReset || e.getSource() == miReset) {//重来
            mainPanel.setLevel();
        }

关于save函数实现将当前进度存入数据库

public void save(int gift,int level,int step,String username) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            conn = JDBCUtils.getConnection();
            String sql = "update user set grift = ?, lever = ? , step = ? where id = ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, gift);
            pstmt.setInt(2, level);
            pstmt.setInt(3,step);
            pstmt.setString(4,username);
            int count = pstmt.executeUpdate();
            if (count > 0) {
                System.out.println("保存:"+step+" "+gift+" "+level+" "+username);
                System.out.println("保存成功");
            } else {
                System.out.println("保存失败");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(pstmt, conn);
        }
    }

(10)实现保存的当前进度功能

else if (e.getSource() == btnLook) {
            JOptionPane.showMessageDialog(this, "咔嚓!时光定格,已经记录下了当前状态期待与你下次的会面");
            System.out.println("test:"+level);
            save(nowgrift,nowlever,nowstep,username);
        }

七、玩家交互代码实现

1.键盘动态交互

(1)实现键盘的监听

public MyPanel() {
            //监听键盘事件
            this.addKeyListener(this);
            setSize(600, 600);
            readFile(level);

        }

(2)读取键盘输入做出响应

public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println(e.getKeyCode());
            nowstep++;
            //方向键左键
            if (e.getKeyCode() == 37) {
                goLeft();
            }
            //方向键向上
            else if (e.getKeyCode() == 38) {
                goUp();
            }
            //方向键向右
            else if (e.getKeyCode() == 39) {
                goRight();
            } //方向键向下
            else if (e.getKeyCode() == 40) {
                goDown();
            }
            if (isWin()) {
            //这是我设置的通关剧情,你们也可以自行输入了!!
                String zf[] = {
                        "很开心一年前你诞生在这个世界!",
                        "现在的你软糯糯的像夏天里的棉花糖",
                        "听说你会啃胡萝卜了,我准备在这个春天给你种下胡萝卜的种子",
                        "我的胡萝卜丰收了!所以今年的礼物是胡萝卜",
                        "送你一罐蜂蜜,但是要小心蛀牙哦",
                };
                nowgrift += needGift;
                endTime =  System.currentTimeMillis();
                System.out.println(endTime);
                JOptionPane.showMessageDialog(null, "小熊:祝你" + level + "岁生日快乐!" + zf[level - 1]);
                setLevel(1);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
        }

(3)判断箱子是否推到位

public boolean isWin() {
            boolean isok = true;
            for (int i = 0; i < 20; i++) {
                for (int j = 0; j < 20; j++) {
                    if ((map[i][j] == 4 || map[i][j] == 9) && tempmap[i][j] != 9) {
                        isok = false;
                        break;
                    }
                }
                if (!isok)
                    break;
            }
            return isok;
        }

2.推箱子过程的实现

拿向上推箱子举例,在这段代码中我们其实也完成了当前步骤的入栈,用于实现之后的撤销一步的功能

public void goUp() {
            //如果向上推到箱子了(人的前面有箱子)
            if (tempmap[mx - 1][my] == 3 || tempmap[mx - 1][my] == 9) {
                //判断箱子的上面是什么,如果是目的地或者是空地就可以推动箱子
                if (tempmap[mx - 2][my] == 2 || tempmap[mx - 2][my] == 4) {
                    //如果箱子推到是是空地
                    if (tempmap[mx - 2][my] == 2) {
                        //交换空地和箱子的位置
                        tempmap[mx - 2][my] = 3;//箱子前面
                        tempmap[mx - 1][my] = 8;//人前面
                    }
                    //如果推到的是目的地
                    else {
                        //改变箱子的状态
                        tempmap[mx - 2][my] = 9;
                        tempmap[mx - 1][my] = 8;
                    }
                    //要与原始地图作对比才可以对原来人的位置进行判断
                    if (map[mx][my] == 4 || map[mx][my] == 9) {
                        tempmap[mx][my] = 4;
                    }
                    //如果推到的是目的地
                    else {
                        tempmap[mx][my] = 2;
                    }
                    //改变人物的三视图状态(暂时还没有找到三视图)
                    mx--;//改变人物的位置
                    step.push(22);
                }
            }
            //如果人的前面是空地
            else if (tempmap[mx - 1][my] == 2 || tempmap[mx - 1][my] == 4 || tempmap[mx - 1][my] == 5) {
                tempmap[mx - 1][my] = 8;
                if (map[mx][my] == 4 || map[mx][my] == 9) {
                    tempmap[mx][my] = 4;
                }
                //如果推到的是目的地
                else {
                    tempmap[mx][my] = 2;
                }
                mx--;
                step.push(2);
            }
            repaint();
        }

制作所遇到的困难和解决方法

1.再制作窗口图标时,无法正常更改窗体做上角的图标。
解决办法,将原先的语句用try-catch异常处理包起来,于是发现是路径设置出现问题(input==null),修改正确 的路径就可以正常显示了。

try{
    Image image = ImageIO.read(this.getClass().getResource(path));
    this.setIconImage(image);
    }
    catch (IOException e){
          e.printStackTrace();
 }

2.登录注册时候,玩家输入是否为空时,我用了判断是否为(null),是否为(“”)都不能完成我想要的功能:输入为空的时候不能注册,最后改为StringUtils.isNullOrEmpty(username),成功解决

if (StringUtils.isNullOrEmpty(username)) {
	JOptionPane.showMessageDialog(null, "小兔子:真是的!你连名字都不告诉我");
	}
	if (StringUtils.isNullOrEmpty(password)) {
 	JOptionPane.showMessageDialog(null, "咦?你忘记了我们之间的暗号!不是不是小兔子乖乖,把门开开啦!");
}