天天看點

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

Java實作推箱子小遊戲(idea+mySQL)

就是我們學校實訓有個推箱子的小遊戲,一開始隻是完成任務,然後……【想法越來越多,我的第一個小遊戲就誕生了,雖然可能就我一個人玩了,但是很高興能和你分享制作的過程!】

完整的白嫖代碼以及資料可以通過下面的百度雲連接配接擷取

(大家可以根據源碼和看文章中對各個闆塊的說明這樣更加清晰一點)

連結:https://pan.baidu.com/s/18LGcssj8ms-A7WgPNH3bwQ 提取碼:yncd

複制這段内容後打開百度網盤手機App,操作更友善哦

遊戲部分功能及部分地圖展示

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

一、遊戲設定

1.玩法

把箱子推到指定的地方,這裡我把箱子替換成了禮物,需要把禮物搬運到指定的地點,就能進入下一關。

2.劇情

小熊要給小兔子過生日,在每一年都會準備不同的禮物,當所有禮物都送達的時候,小熊就會給小兔子送上這一年的生日祝福!小兔子也能按時長大一歲。

二、需求分析

1.使用者登入界面

玩家憑借使用者名和密碼登入,沒有賬号時可以選擇注冊

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

2.遊戲界面

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

(1)窗體标題欄

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

玩家登入成功後就會在窗體的标題欄上顯示使用者昵稱

(2)窗體菜單欄

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

玩家可以在通過菜單欄的點選實作相應的功能

(3)主要按鈕

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法
Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

玩家可以點選按鈕實作相應的功能

(4)主面版

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

玩家可以通過鍵盤,實作小熊位置的移動,箱子的推動,所有箱子推到指定位置(就是小熊爪印的時候)就會自動進入下一關,在右側的版面,有關卡的提示功能,記錄步驟,送達禮物,用時,實作所有玩家的排行(前三名),并在右下角有目前的時間顯示。

三、資料庫設計

1.用MySQL設計存儲玩家資訊的表

這裡我們用到的是mySQL

建立資料庫-> mygame

建立資料表-> user

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

2.為了後續友善操作,我們可以使用idea的Database功能

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

填寫使用者名和密碼一般就可以連接配接成功了,但是MySQL(8.0)好像是要配置時區的

四、需要提前建立的一些接口類

工程總覽

Java實作推箱子小遊戲Java實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

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實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

特别特别要注意,不要多打空格!!!(當初連資料庫的時候就是因為這裡多打了空格找了好久的原因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實作推箱子小遊戲(idea+mySQL)遊戲部分功能及部分地圖展示一、遊戲設定二、需求分析三、資料庫設計四、需要提前建立的一些接口類五、登入視窗實作六、遊戲版面的實作七、玩家互動代碼實作制作所遇到的困難和解決方法

每一關有又相應的由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, "咦?你忘記了我們之間的暗号!不是不是小兔子乖乖,把門開開啦!");
}