用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("退出");
// 添加標簽
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("")) { 當用戶名或密碼文本框內(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)閉當前窗口
new GameFrame();
} else {
JOptionPane.showMessageDialog(this, "用名或密碼錯誤或沒有注冊,請重新輸入或進入注冊?。?!");
new RegistFrame();
name.setText("");// 清空文本框
password.setText("");// 清空文本框
}
} catch (IOException ee) {
}
}
}
if (e.getSource() == exit) {
dk.setVisible(false);// 關(guān)閉當前窗口
}
}
}
這是實現(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("退出");
// 添加標簽
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("")) {// 當用戶名或密碼文本框內(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)閉當前窗口
new LoginFrame();
} else {
JOptionPane.showMessageDialog(this, "該用戶已存在!");
name.setText("");// 清空文本框
password.setText("");// 清空文本框
}
} catch (IOException ee) {
}
}
}
if (e.getSource() == exit) {
dk.setVisible(false);// 關(guān)閉當前窗口
}
}
}
與登錄頁面的代碼差不多。
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()) {
// 顯示勝利的圖標
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); // 將勝利圖標添加到內(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)重復執(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"));// 菜單上的圖標
// 指定圖片位置
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("幫助");
// 將每一個選項下面的條目添加到選項當中
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è)置一個標題為拼圖V2.0的窗口
this.setTitle("拼圖V2.0");
// 設(shè)置界面置頂
this.setAlwaysOnTop(true);
// 設(shè)置界面居中
this.setLocationRelativeTo(null);
// 設(shè)置關(guān)閉模式
this.setDefaultCloseOperation(2); // 根據(jù)參數(shù)的取值不同,做出不同的處理
// 取消默認居中放置,按照XY軸形式添加組件
this.setLayout(null); // 空布局,相當于自定義布局
// 添加鍵盤監(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()方法
// 獲取當前被點擊的條目對象
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)閉當前界面
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);
}
}
}
這里的代碼就顯得復雜一些,它包括窗口組件的實現(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-10
java實現(xiàn)輸出字符串中第一個出現(xiàn)不重復的字符詳解
這篇文章主要介紹了java實現(xiàn)輸出字符串中第一個出現(xiàn)不重復的字符詳解的相關(guān)資料,需要的朋友可以參考下2017-04-04
SpringBoot+jpa配置如何根據(jù)實體類自動創(chuàng)建表
這篇文章主要介紹了SpringBoot+jpa配置如何根據(jù)實體類自動創(chuàng)建表,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
springboot中報錯Invalid character found in
這篇文章主要介紹了springboot中報錯Invalid character found in the request的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
Java springboot接口迅速上手,帶你半小時極速入門
這篇文章主要給大家介紹了關(guān)于SpringBoot實現(xiàn)API接口的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-09-09

