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