用Java編寫一個簡單的拼圖游戲全過程
1.思路與分析
首先我們需要提供幾個面板,一些菜單欄以及一些按鈕,按照你所需要拼成的圖片的一些小切片(可以4*4或者5*5,總之按照你的圖片大小來定),定義一個控制圖片移動的函數(shù),還需要對你的函數(shù)方法及菜單按鈕提供監(jiān)聽,然后我們就可以將這些想法付諸行動了。
2.程序代碼及分析
1.拼圖游戲app總代碼
package op1; public class App { public static void main(String[] args) { // new RegistFrame(); //注冊 new LoginFrame(); //登錄 // new GameFrame(); //游戲 } }
我們由登錄頁面引出其他頁面,先調(diào)用登錄函數(shù),運行代碼時,先彈出登錄頁面
如果輸入為空,則會彈出如下提示框
如果輸入錯誤或者沒有注冊,則會彈出如下提示框
隨后彈出注冊頁面
如果輸入為空,則會彈出如下提示框
如果注冊成功,則會彈出如下提示框
然后便可進入登錄頁面,進行登錄
隨后進入游戲頁面
2.登錄頁面代碼
package op1; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import javax.swing.*; public class LoginFrame extends JFrame implements ActionListener { JFrame dk = new JFrame("登錄"); // 添加按鈕 JButton login = new JButton("登錄"); JButton exit = new JButton("退出"); // 添加標(biāo)簽 JLabel name1 = new JLabel("用戶名"); JLabel pwd1 = new JLabel("密碼"); // 添加文本輸入框 JTextField name = new JTextField(13); JTextField password = new JTextField(13); public LoginFrame() { initLoginJFrame();// 初始化界面 } private void initLoginJFrame() { dk.setSize(210, 200); dk.setAlwaysOnTop(true); // dk.setLocationRelativeTo(null); dk.setDefaultCloseOperation(2); dk.setLayout(new FlowLayout()); dk.add(name1); dk.add(name); dk.add(pwd1); dk.add(password); dk.add(login); dk.add(exit); login.addActionListener(this); exit.addActionListener(this); dk.setVisible(true); } private void initView() { } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == login) { if (name.getText().equals("") || password.getText().equals("")) { 當(dāng)用戶名或密碼文本框內(nèi)的內(nèi)容為空時 JOptionPane.showMessageDialog(this, "用名或密碼不能為空");// 出現(xiàn)對話框提醒 name.setText("");// 清空文本框 password.setText("");// 清空文本框 } else { try { BufferedWriter w = new BufferedWriter(new FileWriter("D:\\用戶信息2.0.txt", true));// true追加錄入,錄入用戶信息 String sum = name.getText() + " " + password.getText();// 用戶名與密碼之間用空格連接 BufferedReader r = new BufferedReader(new FileReader("D:\\用戶信息2.0.txt"));// 讀出用戶信息 String text; Boolean c = false; while ((text = r.readLine()) != null) { if (sum.equals(text)) { // 循環(huán)排查,看錄入的信息是否與讀取的信息相同,如果相同 c = true; } // 則c為true,登陸成功,不同,c為false,則登錄失敗 } if (c == true) { JOptionPane.showMessageDialog(this, "登錄中?。?!"); dk.setVisible(false);// 關(guān)閉當(dāng)前窗口 new GameFrame(); } else { JOptionPane.showMessageDialog(this, "用名或密碼錯誤或沒有注冊,請重新輸入或進入注冊?。?!"); new RegistFrame(); name.setText("");// 清空文本框 password.setText("");// 清空文本框 } } catch (IOException ee) { } } } if (e.getSource() == exit) { dk.setVisible(false);// 關(guān)閉當(dāng)前窗口 } } }
這是實現(xiàn)登錄頁面的函數(shù),為了方便理解,我添加了注釋。
3.注冊頁面代碼
package op1; import javax.swing.*; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class RegistFrame extends JFrame implements ActionListener { JFrame dk = new JFrame("注冊"); // 添加按鈕 JButton regist = new JButton("注冊"); JButton exit = new JButton("退出"); // 添加標(biāo)簽 JLabel name1 = new JLabel("用戶名"); JLabel pwd1 = new JLabel("密碼"); // 添加文本輸入框 JTextField name = new JTextField(13); JTextField password = new JTextField(13); public RegistFrame() { initregistJFrame();// 初始化界面 } private void initregistJFrame() { dk.setSize(210, 200); dk.setAlwaysOnTop(true); dk.setLocationRelativeTo(null); dk.setLocation(200, 200); // 設(shè)置窗口位置 dk.setDefaultCloseOperation(2); dk.setLayout(new FlowLayout()); dk.add(name1); dk.add(name); dk.add(pwd1); dk.add(password); dk.add(regist); dk.add(exit); regist.addActionListener(this); exit.addActionListener(this); dk.setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == regist) { if (name.getText().equals("") || password.getText().equals("")) {// 當(dāng)用戶名或密碼文本框內(nèi)的內(nèi)容為空時 JOptionPane.showMessageDialog(this, "用戶名或密碼不能為空"); // 出現(xiàn)對話框提醒 name.setText("");// 清空文本框 password.setText("");// 清空文本框 } else { try { BufferedWriter w = new BufferedWriter(new FileWriter("D:\\用戶信息2.0.txt", true));// true追加錄入,錄入用戶信息 String sum = name.getText() + " " + password.getText();// 用戶名與密碼之間用空格連接 BufferedReader r = new BufferedReader(new FileReader("D:\\用戶信息2.0.txt"));// 讀出用戶信息 Boolean c = true; String text; while ((text = r.readLine()) != null) { if (sum.equals(text)) { // 循環(huán)排查,看錄入的信息是否與讀取的信息相同,如果相同 c = false; // 則c為false,該用戶已存在,不同,c為true,則注冊成功 } } if (c == true) { w.write(sum); // 將信息寫入文件 w.newLine();// 生成換行符 w.close();// 關(guān)閉文件 r.close(); JOptionPane.showMessageDialog(this, "注冊成功!"); dk.setVisible(false);// 關(guān)閉當(dāng)前窗口 new LoginFrame(); } else { JOptionPane.showMessageDialog(this, "該用戶已存在!"); name.setText("");// 清空文本框 password.setText("");// 清空文本框 } } catch (IOException ee) { } } } if (e.getSource() == exit) { dk.setVisible(false);// 關(guān)閉當(dāng)前窗口 } } }
與登錄頁面的代碼差不多。
4.游戲頁面代碼
package op1; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; import javax.swing.*; import javax.swing.border.BevelBorder; public class GameFrame extends JFrame implements KeyListener, ActionListener {// 繼承一個,實現(xiàn)兩個接口 // JFrame 界面,窗體 // GameFrame即游戲主界面 // 與游戲相關(guān)的邏輯都比在此JavaBean類中 // 創(chuàng)建一個二維數(shù)組,加載圖片 int[][] data = new int[4][4]; // 記錄空白格在二維數(shù)組中的位置 int x = 0; int y = 0; // 定義二維數(shù)組,正確存儲數(shù)據(jù),即拼圖勝利時,圖片的正確順序 int[][] win = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 0 } }; // 定義變量統(tǒng)計步數(shù) int step = 0; // 創(chuàng)建菜單選項相關(guān)的對象(這幾項之所以放在initJMenuBar()之外,是因為后面方法重寫時要調(diào)用) JMenuItem replayItem = new JMenuItem("重新游戲"); // 菜單項,創(chuàng)建選項下面的條目對象 JMenuItem closeItem = new JMenuItem("退出"); JMenuItem accountItem = new JMenuItem("關(guān)于我們"); JMenuItem reLoginItem = new JMenuItem("重新登錄"); public GameFrame() { initJFrame();// 初始化界面 initJMenuBar();// 初始化菜單 initData();// 初始化數(shù)據(jù)(打亂數(shù)據(jù)) initImage();// 初始化圖片(根據(jù)打亂的結(jié)果加載圖片) this.setVisible(true);// 讓界面顯示出來,可視化 } // 初始化數(shù)據(jù)(打亂數(shù)據(jù)) private void initData() { // 定義一維數(shù)組 int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // 打亂數(shù)組中的數(shù)據(jù)的順序,遍歷數(shù)組 Random r = new Random(); // 產(chǎn)生隨機數(shù)r for (int i = 0; i < arr.length; i++) { // 獲取到隨機索引 int index = r.nextInt(arr.length); // 將數(shù)組中的每一個元素與隨機索引上的數(shù)據(jù)進行交換 int temp = arr[i]; arr[i] = arr[index]; arr[index] = temp; } // 遍歷一維數(shù)組arr中的每一個元素,并依次添加到二維數(shù)組中 for (int i = 0; i < arr.length; i++) { if (arr[i] == 0) { // 確定空白格的位置 x = i / 4; y = i % 4; } data[i / 4][i % 4] = arr[i]; // 一維數(shù)組轉(zhuǎn)二維數(shù)組,并打亂順序 } } // 按二維數(shù)組中管理的數(shù)據(jù)添加圖片 private void initImage() { // 清空原本已經(jīng)出現(xiàn)的所有圖片 this.getContentPane().removeAll(); // 將方框里的內(nèi)容全部清除 if (victory()) { // 顯示勝利的圖標(biāo) JLabel winJLabel = new JLabel(new ImageIcon("E:/JAVA/OP1/OP1/win.png")); winJLabel.setBounds(203, 283, 197, 73); // 距屏幕左面203個像素,上方283個像素,窗口寬197,長73 this.getContentPane().add(winJLabel); // 將勝利圖標(biāo)添加到內(nèi)容方框 } JLabel stepCount = new JLabel("步數(shù):" + step); stepCount.setBounds(50, 30, 100, 20); this.getContentPane().add(stepCount); // 將步數(shù)添加到內(nèi)容方框 // 先加載的圖片在上方,后加載的圖片在下面 // 外循環(huán):將內(nèi)循環(huán)重復(fù)執(zhí)行4次 for (int i = 0; i < 4; i++) { // 內(nèi)循環(huán):一行添加4張圖片,例:第一行(0,0),(0,1),(0,2),(0,3) for (int j = 0; j < 4; j++) { // 獲取要加載圖片序號 int num = data[i][j]; // 創(chuàng)建JLabel的對象(管理容器) JLabel jLabel = new JLabel(new ImageIcon("E:/JAVA/op1/op1/" + num + ".jpg"));// 菜單上的圖標(biāo) // 指定圖片位置 jLabel.setBounds(105 * j + 90, 105 * i + 130, 105, 105); // 圖片添加邊框,0:凸,1:凹 jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED)); // 把管理容器添加到界面 this.getContentPane().add(jLabel); } } // 添加背景圖片 JLabel background = new JLabel(new ImageIcon("E:/JAVA/op1/op1/background.png")); background.setBounds(50, 40, 508, 560); // 把背景圖片添加到界面 this.getContentPane().add(background); // 刷新界面 this.getContentPane().repaint(); } private void initJMenuBar() { // 總菜單,菜單條 // 創(chuàng)建菜單對象 JMenuBar jMenuBar = new JMenuBar(); // 創(chuàng)建菜單上面的兩個選項的對象 JMenu functionJMenu = new JMenu("功能"); // 子菜單,創(chuàng)建兩個菜單選項的對象 JMenu aboutJMenu = new JMenu("幫助"); // 將每一個選項下面的條目添加到選項當(dāng)中 functionJMenu.add(replayItem); functionJMenu.add(reLoginItem); functionJMenu.add(closeItem); aboutJMenu.add(accountItem); // 給條目綁定事件,以便實現(xiàn)動作監(jiān)聽 replayItem.addActionListener(this); // 添加動作監(jiān)聽,則必有ActionListener接口,必有唯一的方法重寫 closeItem.addActionListener(this); accountItem.addActionListener(this); reLoginItem.addActionListener(this); // 將兩個選項添加到菜單 jMenuBar.add(functionJMenu); jMenuBar.add(aboutJMenu); //設(shè)置菜單 this.setJMenuBar(jMenuBar); } private void initJFrame() { // 設(shè)置界面的寬高 this.setSize(700, 700); // 設(shè)置一個標(biāo)題為拼圖V2.0的窗口 this.setTitle("拼圖V2.0"); // 設(shè)置界面置頂 this.setAlwaysOnTop(true); // 設(shè)置界面居中 this.setLocationRelativeTo(null); // 設(shè)置關(guān)閉模式 this.setDefaultCloseOperation(2); // 根據(jù)參數(shù)的取值不同,做出不同的處理 // 取消默認(rèn)居中放置,按照XY軸形式添加組件 this.setLayout(null); // 空布局,相當(dāng)于自定義布局 // 添加鍵盤監(jiān)聽事件 this.addKeyListener(this); // 添加鍵盤監(jiān)聽,觸發(fā)KeyEvent事件,調(diào)用三種方法,看情況選擇 } @Override public void keyTyped(KeyEvent e) { // 調(diào)用keyTyped()方法,并重寫 } // 如果是65,就是按下不松調(diào)用的方法,如果是112,就是按下松開調(diào)用的方法 @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); if (code == 112 || code == 65) { // 112代表F1,65代表A,查看原圖 // 刪除界面中所有圖片 this.getContentPane().removeAll(); // 加載已經(jīng)拼好原圖 JLabel all = new JLabel(new ImageIcon("E:/JAVA/OP1/OP1/all.jpg")); all.setBounds(30, 70, 420, 420); this.getContentPane().add(all); // 加載背景圖片 // JLabel background = new JLabel(new ImageIcon("background.png")); // background.setBounds(30, 30, 400, 500); // 把背景圖片添加到界面 // this.getContentPane().add(background); // 刷新界面 this.getContentPane().repaint(); } } // 松開按鍵時調(diào)用的方法 @Override public void keyReleased(KeyEvent e) { // 判斷游戲是否勝利,if勝,直接結(jié)束,不再執(zhí)行之后的移動代碼 if (victory()) { // 結(jié)束方法 return; } // 判斷左:37 上:38 右:39 下:40 討論四種情況 int code = e.getKeyCode(); // 采用鍵碼值 System.out.println(code); if (code == 37) { System.out.println("向左移動"); if (y == 3) { return; } // 空白格右方的數(shù)字往左移動 data[x][y] = data[x][y + 1]; // 交換所移動圖片與空白格的位置 data[x][y + 1] = 0; y++; // 空白格位置改動,所以y++ // 每移動一次,計數(shù)器就自增一次 step++; // 調(diào)用方法按照最新的數(shù)字加載圖片 initImage(); } else if (code == 38) { System.out.println("向上移動"); if (x == 3) { // 空白格已經(jīng)在最下方,無圖片可移 return; } // 空白格下方的數(shù)字往上移動 // x,y 表示空白格;x + 1,y 表示空白格下方數(shù)字 // 空白格下方的數(shù)字賦值給空白格 data[x][y] = data[x + 1][y]; data[x + 1][y] = 0; x++; // 每移動一次,計數(shù)器就自增一次 step++; // 調(diào)用方法按照最新的數(shù)字加載圖片 initImage(); } else if (code == 39) { System.out.println("向右移動"); if (y == 0) { return; } // 空白格左方的數(shù)字往右移動 data[x][y] = data[x][y - 1]; data[x][y - 1] = 0; y--; // 每移動一次,計數(shù)器就自增一次 step++; // 調(diào)用方法按照最新的數(shù)字加載圖片 initImage(); } else if (code == 40) { System.out.println("向下移動"); if (x == 0) { return; } // 空白格上方的數(shù)字往下移動 data[x][y] = data[x - 1][y]; data[x - 1][y] = 0; x--; // 每移動一次,計數(shù)器就自增一次 step++; // 調(diào)用方法按照最新的數(shù)字加載圖片 initImage(); } else if (code == 65) { // 65代表A,刷新界面 initImage(); } else if (code == 87) { // 87代表W,作弊碼,一鍵生成 data = new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 }, { 13, 14, 15, 0 } }; initImage(); } } // 判斷data數(shù)組中的數(shù)據(jù)是否跟win數(shù)組中相同 // 如果全部相同,返回true。否則返回false public boolean victory() { for (int i = 0; i < data.length; i++) { // i : 依次表示二維數(shù)組data里面的索引 // data[i]:依次表示每一個一維數(shù)組 for (int j = 0; j < data[i].length; j++) { if (data[i][j] != win[i][j]) { // 只要有一個數(shù)據(jù)不一樣,則返回false return false; } } } // 循環(huán)結(jié)束表示數(shù)組遍歷比較完畢,全都一樣返回true return true; } @Override public void actionPerformed(ActionEvent e) { // 方法重寫,并實現(xiàn)ActionEvent類的getSource()方法 // 獲取當(dāng)前被點擊的條目對象 Object obj = e.getSource(); // 判斷 if (obj == replayItem) { System.out.println("重新游戲"); // 計步器清零 step = 0; // 再次打亂二維數(shù)組中的數(shù)據(jù) initData(); // 重新加載圖片 initImage(); } else if (obj == reLoginItem) { System.out.println("重新登錄"); // 關(guān)閉當(dāng)前界面 this.setVisible(false); // 返回登錄界面 new LoginFrame(); } else if (obj == closeItem) { System.out.println("關(guān)閉游戲"); // 直接關(guān)閉虛擬機 System.exit(0); } else if (obj == accountItem) { System.out.println("關(guān)于我們"); // 創(chuàng)建彈框?qū)ο? JDialog jDialog = new JDialog(); // 發(fā)現(xiàn)新大陸,實現(xiàn)彈窗 // 創(chuàng)建管理圖片的容器對象JLabel // JLabel jLabel = new JLabel(new ImageIcon("about.png")); // 設(shè)置位置和寬高 // jLabel.setBounds(0,0,258,258); // 把圖片添加到彈框 // jDialog.getContentPane().add(jLabel); // 彈框大小 jDialog.setSize(344, 344); // 設(shè)置提示語 JLabel clue = new JLabel("按F1或長按A顯示原圖,按A刷新一下,按W一鍵拼好"); clue.setBounds(0, 0, 100, 20); jDialog.getContentPane().add(clue); // 彈框置頂 jDialog.setAlwaysOnTop(true); // 彈框居中 jDialog.setLocationRelativeTo(null); // 彈框不關(guān)閉則無法操作下面的界面 jDialog.setModal(true); // 彈框顯示出來 jDialog.setVisible(true); } } }
這里的代碼就顯得復(fù)雜一些,它包括窗口組件的實現(xiàn),事件監(jiān)聽的實現(xiàn),以及拼圖移動的實現(xiàn),如果拼圖成功,則會彈出拼圖成功的提示圖片。
3.總結(jié)
以上就是就是簡單的拼游戲的代碼的實現(xiàn)及分析,大家有興趣可以自己去試試
到此這篇關(guān)于用Java編寫一個簡單的拼圖游戲的文章就介紹到這了,更多相關(guān)Java編寫拼圖游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解微信開發(fā)之a(chǎn)ccess_token之坑
access_token分類一是普通access_token,二是網(wǎng)頁授權(quán)access_token。這篇文章主要介紹了詳解微信開發(fā)之a(chǎn)ccess_token之坑,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-10-10java實現(xiàn)輸出字符串中第一個出現(xiàn)不重復(fù)的字符詳解
這篇文章主要介紹了java實現(xiàn)輸出字符串中第一個出現(xiàn)不重復(fù)的字符詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04SpringBoot+jpa配置如何根據(jù)實體類自動創(chuàng)建表
這篇文章主要介紹了SpringBoot+jpa配置如何根據(jù)實體類自動創(chuàng)建表,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11springboot中報錯Invalid character found in
這篇文章主要介紹了springboot中報錯Invalid character found in the request的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09Java springboot接口迅速上手,帶你半小時極速入門
這篇文章主要給大家介紹了關(guān)于SpringBoot實現(xiàn)API接口的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-09-09