1. 程式人生 > >【java】JavaFX從零開始實現拼圖小遊戲

【java】JavaFX從零開始實現拼圖小遊戲

最近java課老師佈置了一個作業:製作一個拼圖小遊戲,關鍵老師自己說javaGUI程式設計沒用,講課的時候好像跳過了(沒去上課不過我猜應該沒講吧),現在又叫我們做這些,實在是哭笑不得。

得了吧,老師的任務只能老老實實完成對吧,但是我又想到像Swing這些工具包已經基本上被淘汰了,做出來的頁面有點老土,要學就學點好的,於是我選擇用JavaFX來完成這次作業。

JavaFX的發展也不容樂觀,一直不溫不火的,但是本著對桌面應用有著一定的興趣,就學一學吧,於是學了半天后開始上手做出來這個極其簡陋的拼圖遊戲,希望隨之以後的深入學習,能夠做出更精美的應用。

 

(一)首頁介面

 首頁就很簡單,一個VBox作為父佈局,巢狀一個HBox子佈局,HBox子佈局裡寫三個Button事件,點選後開啟指定難度的窗體,並關閉首頁窗體,下面的文字是放在父佈局VBox裡的Label的文字內容,至於背景和按鈕顏色則是用css來指定,整個過程唯一要關注的就是各個按鈕大小間距位置等等。

 

(二)遊戲介面

在遊戲中我設定了三種難度,分別是3*3,4*4,5*5,實現上基本一樣,所以只講第一個簡單難度九宮格的實現即可。

點選簡單按鈕後,關閉首頁視窗,開啟遊戲視窗:

講這個頁面的難點(其實也很簡單):

(1) 圖片的擷取:我當然不是PS去把一張圖片截成一塊塊圖片啦,這裡我用imageview.setViewPort(new Rectangle2D (x,y,width,higth))的方法進行切割,可以指定圖片從哪兒開始切,以及需要的圖片大小

(2)圖片的儲存:利用圖片陣列ImageView[ ]儲存切割好的圖片即可,每一個數組元素裡就是完整圖片的一個子圖片

(3)圖片在九宮格中的擺放:利用GridPane佈局,可以指定在佈局裡圖片的位置,達到九宮格的效果

(4)圖片擺放後必須有解:學名叫N數碼問題,看了一些大神的部落格以下結論:

                       當列數為奇數時,一切操作不影響奇偶性,當前狀態逆序數為偶數等價於拼圖有解

                       當列數為偶數時,上下交換影響奇偶性,只要當前狀態逆序數奇偶性^當前空格狀態的奇偶性=偶數等價於拼圖有解

(5)實現拼圖有解:由上面的結論我們可以這樣,從[0-8]中隨機取8個不重複的數字,保證這串數字的逆序數為偶數,例如:[2 0 1 3 4 5 6 7],沒有獲得的數字為[8],首先令索引為8圖片陣列儲存一個空白圖片,然後我們把這串數字作為圖片陣列i的下標,分別把圖片放在對應九宮格的位置,如:

i[2]  i[0]  i[1]

i[3]  i[4]  i[5]

i[6]  i[7]  i[8]----->儲存空白圖片

(6)圖片的移動:點選空白格子周圍的格子,實現圖片在佈局中的位置交換即可,如點選i[7]實現交換:

i[2]  i[0]  i[1]

i[3]  i[4]  i[5]

i[6]  i[8]   i[7]

(7)如何算作拼圖成功:每一次圖片交換,就檢查是否拼圖成功,至於是否拼圖成功想必可以很直觀的看出來,我們是順序切割圖片再順序儲存,因此像這樣就能判定成功:

i[0]  i[1]  i[2]    

i[3]  i[4]  i[5]

i[6]  i[7]  i[8]   

8判定拼圖成功:我們需要判定陣列下標是不是在它需要對應的位置,數學化後的公式為:n = 3 * r + c,n為陣列下標,r為行的索引,c為列的索引,如i[4]下標為4,行索引為1,列索引為1,可得:4=n=1*3+1=4,顯然可證該圖片所處的位置是正確的

(9)下方按鈕事件:返回首頁即關閉當前視窗再開啟首頁視窗,重新遊戲即關閉當前視窗再開啟遊戲視窗,顯示原圖相當於提示功能,在不關閉當前視窗的前提下,開啟另一個顯示完整圖片的視窗

 

(三)遊戲成功介面

沒什麼難度,當檢測拼圖成功時彈出一個文字框即可。

 

(四)原始碼部分

(1)首頁介面

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;

/**
*開始選單主介面
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class Start extends Application {

	@Override
	public void start(Stage primaryStage) {
		try {
			// 父容器
			VBox vBox = new VBox();

			// 子容器,分別是按鈕和輸出文字
			HBox hBox_1 = new HBox();
			HBox hBox_2 = new HBox();

			// 顯示難度選擇按鈕
			Button start_1 = new Button("簡單");
			start_1.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent arg0) {
					// 開啟另一個視窗,即遊戲視窗
					Game_1 game_1 = new Game_1();
					game_1.start(new Stage());
					// 關閉開始介面
					primaryStage.close();
				}
			});
			Button start_2 = new Button("困難");
			start_2.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent arg0) {
					// 開啟另一個視窗,即遊戲視窗
					Game_2 game_2 = new Game_2();
					game_2.start(new Stage());
					// 關閉開始介面
					primaryStage.close();
				}
			});
			Button start_3 = new Button("地獄");
			start_3.setOnAction(new EventHandler<ActionEvent>() {
				@Override
				public void handle(ActionEvent arg0) {
					// 開啟另一個視窗,即遊戲視窗
					Game_3 game_3 = new Game_3();
					game_3.start(new Stage());
					// 關閉開始介面
					primaryStage.close();
				}
			});

			Label label = new Label("@餘氏出品,必屬渣品");
			//設定文字樣式大小和顏色
			label.setFont(new Font("Arial", 30));
			label.setTextFill(Color.web("black"));
			
			hBox_1.getChildren().addAll(start_1, start_2, start_3);
			hBox_2.getChildren().add(label);
			vBox.getChildren().addAll(hBox_1, hBox_2);

			// 設定按鈕大小並調節位置
			start_1.setPrefSize(100, 60);
			start_2.setPrefSize(100, 60);
			start_3.setPrefSize(100, 60);
			hBox_1.setPadding(new Insets(650, 100, 0, 175));
			hBox_2.setPadding(new Insets(50, 50, 500, 260));
			// 設定控制元件之間的距離
			hBox_1.setSpacing(100);

			// 標題欄圖示
			Image image = new Image("application/4.jpg");

			Scene scene = new Scene(vBox, 800, 800);
			scene.getStylesheets().add(getClass().getResource("Start.css").toExternalForm());
			primaryStage.getIcons().add(image);
			primaryStage.setTitle("智障拼圖");
			primaryStage.setScene(scene);
			primaryStage.setResizable(false);
			primaryStage.show();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		launch(args);
	}
}

(2)簡單難度的遊戲介面 

import java.util.Random;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
/**
*遊戲介面----簡單
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class Game_1 extends Application {
	public int m; // m是不在隨機陣列的那個數字
	ImageView[] imageViews = new ImageView[9];

	@Override
	public void start(Stage primaryStage) {
		init(primaryStage);

	}

	public void init(Stage primaryStage) {
		// 父佈局
		VBox vBox = new VBox();

		// 3*3九宮格佈局,作為上方的選項巢狀入父佈局
		GridPane gridPane = new GridPane();

		// 水平佈局,作為下方的選項巢狀入父佈局
		HBox hbox = new HBox();
		hbox.setPadding(new Insets(10)); // 填充
		hbox.setAlignment(Pos.CENTER); // 居中

		// 新增3個點選
		Button home = new Button("返回首頁");
		home.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即首頁視窗
				Start start = new Start();
				start.start(new Stage());
				// 關閉原本介面
				primaryStage.close();
			}
		});
		Button again = new Button("重新遊戲");
		again.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即遊戲視窗
				Game_1 game = new Game_1();
				game.start(new Stage());
				// 關閉原本介面
				primaryStage.close();
			}
		});
		Button look = new Button("檢視原圖");
		look.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即顯示原圖
				OnImage_1 OnImage = new OnImage_1();
				OnImage.start(new Stage());
			}
		});
		// 設定按鈕大小並居中
		home.setPrefSize(200, 50);
		again.setPrefSize(200, 50);
		look.setPrefSize(200, 50);
		// 設定控制元件之間的距離
		hbox.setSpacing(100);

		hbox.getChildren().addAll(home,again, look);

		// 遊戲部分
		/*
		 * 自定義的函式,產生逆序數為偶數的不重複陣列,依次作為圖片陣列的下標,例如: 2 0 1 3 4 5 6 7 ------>,此時m=8,變成如下即為正確:
		 * 0 1 2 3 4 5 4 7
		 */
		int[] n = random();

		Image image2 = new Image("application/2.jpg");

		for (int i = 0; i < 9; i++) {
			imageViews[i] = new ImageView(image2); // 初始化陣列
			imageViews[i].setOnMouseClicked(new myevent()); // 設定點選事件
		}
		for (int i = 0, k = 0; i <= 2; i++) {
			for (int j = 0; j <= 2; j++, k++) {
				imageViews[k].setViewport(new Rectangle2D(250 * j, 250 * i, 250, 250)); // 切割圖片分配給圖片陣列
			}
		}
		// 按照產生的隨機數將imageView陣列加入面板
		gridPane.add(imageViews[n[0]], 0, 0);
		gridPane.add(imageViews[n[1]], 1, 0);
		gridPane.add(imageViews[n[2]], 2, 0);
		gridPane.add(imageViews[n[3]], 0, 1);
		gridPane.add(imageViews[n[4]], 1, 1);
		gridPane.add(imageViews[n[5]], 2, 1);
		gridPane.add(imageViews[n[6]], 0, 2);
		gridPane.add(imageViews[n[7]], 1, 2);
		m = findnum(n); // 找出那個不在隨機數組裡面的數字

		Image image1 = new Image("application/3.jpg"); // 3.png為一個透明圖,放在空格子中
		imageViews[m].setImage(image1);
		gridPane.add(imageViews[m], 2, 2);
		gridPane.setGridLinesVisible(true);
		gridPane.setPrefWidth(800);
		gridPane.setPrefHeight(700);
		vBox.getChildren().add(gridPane);
		// 佈局巢狀,選項部分
		vBox.getChildren().add(hbox);

		// 標題欄圖示
		Image image = new Image("application/4.jpg");

		Scene scene = new Scene(vBox, 800, 800);
		scene.getStylesheets().add(getClass().getResource("Game.css").toExternalForm());
		primaryStage.getIcons().add(image);
		primaryStage.setTitle("智障拼圖");
		primaryStage.setScene(scene);
		primaryStage.setResizable(false);
		primaryStage.show();
	}

	public int[] random() { // 生成8個不重複的逆序數為偶數的數字,這樣拼圖才有結
		int[] ran = new int[8];
		while (iso(ran) == false) {
			ran = random_num();
		}
		return ran;

	}

	public int[] random_num() { // 生成8個不重複數
		int r[] = new int[8];
		Random random = new Random();
		for (int i = 0; i < 8; ++i) {
			r[i] = random.nextInt(9);
			for (int j = 0; j < i; ++j) {
				while (r[i] == r[j]) {
					i--;
					break;
				}
			}
		}
		return r;
	}

	// 判斷逆序數是否為偶數
	public boolean iso(int[] num) {
		int sum = 0;
		for (int i = 0; i <= 6; ++i) {
			for (int j = i; j <= 7; j++) {
				if (num[i] > num[j]) {
					sum++;
				}
			}
		}
		if ((sum % 2) == 0 && sum != 0) {
			return true;
		}

		return false;

	}

	// 點選事件的實現
	class myevent implements EventHandler<MouseEvent> {

		@Override
		public void handle(MouseEvent arg0) {

			ImageView img = (ImageView) arg0.getSource();
			double sx = img.getLayoutX();
			double sy = img.getLayoutY();
			double dispx = sx - imageViews[m].getLayoutX();
			double dispy = sy - imageViews[m].getLayoutY();
			if ((dispx == -250) && (dispy == 0)) { // 點選的空格左邊的格子
				swapimg(img, imageViews[m]); // 交換imageView
				if (issucc(imageViews)) { // 判斷是否拼成功
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}

			else if ((dispx == 0) && (dispy == -250)) { // 上面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 250) && (dispy == 0)) { // 右邊的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 0) && (dispy == 250)) { // 下面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}
		}

		// 交換兩個imageView的實現
		public void swapimg(ImageView i1, ImageView i2) {
			int row1 = GridPane.getRowIndex(i1);
			int colu1 = GridPane.getColumnIndex(i1);
			int row2 = GridPane.getRowIndex(i2);
			int colu2 = GridPane.getColumnIndex(i2);
			GridPane.setRowIndex(i1, row2);
			GridPane.setColumnIndex(i1, colu2);
			GridPane.setRowIndex(i2, row1);
			GridPane.setColumnIndex(i2, colu1);
		}
	}

	// 判斷是否拼圖成功
	public boolean issucc(ImageView[] imageViews) {
		for (int i = 0; i <= 8; ++i) {
			if (i != 3 * GridPane.getRowIndex(imageViews[i]) + GridPane.getColumnIndex(imageViews[i])) {
				return false;
			}
		}
		return true;
	}

	// 找出m
	public int findnum(int[] n) {
		for (int j = 0; j <= 8; ++j) {
			if ((j == n[0]) || (j == n[1]) || (j == n[2]) || (j == n[3]) || (j == n[4]) || (j == n[5]) || (j == n[6])
					|| (j == n[7])) {
			} else {
				return j;
			}
		}
		return -1;
	}

}

(3)困難難度的遊戲介面 

import java.util.Random;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
/**
*遊戲介面----困難
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class Game_2 extends Application {
	public int m; // m是不在隨機陣列的那個數字
	ImageView[] imageViews = new ImageView[16];

	@Override
	public void start(Stage primaryStage) {
		init(primaryStage);

	}

	public void init(Stage primaryStage) {
		// 父佈局
		VBox vBox = new VBox();

		// 3*3九宮格佈局,作為上方的選項巢狀入父佈局
		GridPane gridPane = new GridPane();

		// 水平佈局,作為下方的選項巢狀入父佈局
		HBox hbox = new HBox();
		hbox.setPadding(new Insets(10)); // 填充
		hbox.setAlignment(Pos.CENTER); // 居中

		// 新增3個點選
		Button home = new Button("返回首頁");
		home.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即首頁視窗
				Start start = new Start();
				start.start(new Stage());
				// 關閉原本介面
				primaryStage.close();
			}
		});
		Button again = new Button("重新遊戲");
		again.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即遊戲視窗
				Game_2 game = new Game_2();
				game.start(new Stage());
				// 關閉開始介面
				primaryStage.close();
			}
		});
		Button look = new Button("檢視原圖");
		look.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即顯示原圖
				OnImage_2 OnImage = new OnImage_2();
				OnImage.start(new Stage());
			}
		});
		// 設定按鈕大小並居中
		home.setPrefSize(200, 50);
		again.setPrefSize(200, 50);
		look.setPrefSize(200, 50);
		// 設定控制元件之間的距離
		hbox.setSpacing(100);

		hbox.getChildren().addAll(home,again, look);

		// 遊戲部分
		/*
		 * 自定義的函式,產生逆序數為偶數的不重複陣列,依次作為圖片陣列的下標,例如: 2 0 1 3 4 5 6 7 ------>,此時m=8,變成如下即為正確:
		 * 0 1 2 3 4 5 4 7
		 */
		int[] n = random();

		Image image2 = new Image("application/2_1.jpg");

		for (int i = 0; i < 16; i++) {
			imageViews[i] = new ImageView(image2); // 初始化陣列
			imageViews[i].setOnMouseClicked(new myevent()); // 設定點選事件
		}
		for (int i = 0, k = 0; i <= 3; i++) {
			for (int j = 0; j <= 3; j++, k++) {
				imageViews[k].setViewport(new Rectangle2D(150 * j, 150 * i, 150, 150)); // 切割圖片分配給圖片陣列
			}
		}
		// 按照產生的隨機數將imageView陣列加入面板
		gridPane.add(imageViews[n[0]], 0, 0);
		gridPane.add(imageViews[n[1]], 1, 0);
		gridPane.add(imageViews[n[2]], 2, 0);
		gridPane.add(imageViews[n[3]], 3, 0);
		gridPane.add(imageViews[n[4]], 0, 1);
		gridPane.add(imageViews[n[5]], 1, 1);
		gridPane.add(imageViews[n[6]], 2, 1);
		gridPane.add(imageViews[n[7]], 3, 1);
		gridPane.add(imageViews[n[8]], 0, 2);
		gridPane.add(imageViews[n[9]], 1, 2);
		gridPane.add(imageViews[n[10]], 2, 2);
		gridPane.add(imageViews[n[11]], 3, 2);
		gridPane.add(imageViews[n[12]], 0, 3);
		gridPane.add(imageViews[n[13]], 1, 3);
		gridPane.add(imageViews[n[14]], 2, 3);
		m = findnum(n); // 找出那個不在隨機數組裡面的數字

		Image image1 = new Image("application/3.jpg"); // 3.png為一個透明圖,放在空格子中
		imageViews[m].setImage(image1);
		gridPane.add(imageViews[m], 3, 3);
		gridPane.setGridLinesVisible(true);
		gridPane.setPrefWidth(800);
		gridPane.setPrefHeight(700);
		vBox.getChildren().add(gridPane);
		// 佈局巢狀,選項部分
		vBox.getChildren().add(hbox);

		// 標題欄圖示
		Image image = new Image("application/4.jpg");

		Scene scene = new Scene(vBox, 800, 800);
		scene.getStylesheets().add(getClass().getResource("Game.css").toExternalForm());
		primaryStage.getIcons().add(image);
		primaryStage.setTitle("智障拼圖");
		primaryStage.setScene(scene);
		primaryStage.setResizable(false);
		primaryStage.show();
	}

	public int[] random() { // 生成15個不重複的逆序數為偶數的數字,這樣拼圖才有結
		int[] ran = new int[15];
		while (iso(ran) == false) {
			ran = random_num();
		}
		return ran;

	}

	public int[] random_num() { // 生成15個不重複數
		int r[] = new int[15];
		Random random = new Random();
		for (int i = 0; i < 15; ++i) {
			r[i] = random.nextInt(16);
			for (int j = 0; j < i; ++j) {
				while (r[i] == r[j]) {
					i--;
					break;
				}
			}
		}
		return r;
	}

	// 判斷逆序數是否為偶數
	public boolean iso(int[] num) {
		int sum = 0;
		for (int i = 0; i <= 13; ++i) {
			for (int j = i; j <= 14; j++) {
				if (num[i] > num[j]) {
					sum++;
				}
			}
		}
		if ((sum % 2) == 0 && sum != 0) {
			return true;
		}

		return false;

	}

	// 點選事件的實現
	class myevent implements EventHandler<MouseEvent> {

		@Override
		public void handle(MouseEvent arg0) {

			ImageView img = (ImageView) arg0.getSource();
			double sx = img.getLayoutX();
			double sy = img.getLayoutY();
			double dispx = sx - imageViews[m].getLayoutX();
			double dispy = sy - imageViews[m].getLayoutY();
			if ((dispx == -150) && (dispy == 0)) { // 點選的空格左邊的格子
				swapimg(img, imageViews[m]); // 交換imageView
				if (issucc(imageViews)) { // 判斷是否拼成功
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}

			else if ((dispx == 0) && (dispy == -150)) { // 上面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 150) && (dispy == 0)) { // 右邊的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 0) && (dispy == 150)) { // 下面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}
		}

		// 交換兩個imageView的實現
		public void swapimg(ImageView i1, ImageView i2) {
			int row1 = GridPane.getRowIndex(i1);
			int colu1 = GridPane.getColumnIndex(i1);
			int row2 = GridPane.getRowIndex(i2);
			int colu2 = GridPane.getColumnIndex(i2);
			GridPane.setRowIndex(i1, row2);
			GridPane.setColumnIndex(i1, colu2);
			GridPane.setRowIndex(i2, row1);
			GridPane.setColumnIndex(i2, colu1);
		}
	}

	// 判斷是否拼圖成功
	public boolean issucc(ImageView[] imageViews) {
		for (int i = 0; i <= 15; ++i) {
			if (i != 3 * GridPane.getRowIndex(imageViews[i]) + GridPane.getColumnIndex(imageViews[i])) {
				return false;
			}
		}
		return true;
	}

	// 找出m
	public int findnum(int[] n) {
		for (int j = 0; j <= 15; ++j) {
			if ((j == n[0]) || (j == n[1]) || (j == n[2]) || (j == n[3]) || (j == n[4]) || (j == n[5]) || (j == n[6])
					|| (j == n[7])|| (j == n[8]) || (j == n[9]) || (j == n[10]) || (j == n[11]) || (j == n[12])
					|| (j == n[13]) || (j == n[14]) ) {
			} else {
				return j;
			}
		}
		return -1;
	}

}

(4) 地獄難度的遊戲介面

import java.util.Random;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
/**
*遊戲介面----困難
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class Game_3 extends Application {
	public int m; // m是不在隨機陣列的那個數字
	ImageView[] imageViews = new ImageView[25];

	@Override
	public void start(Stage primaryStage) {
		init(primaryStage);

	}

	public void init(Stage primaryStage) {
		// 父佈局
		VBox vBox = new VBox();

		// 3*3九宮格佈局,作為上方的選項巢狀入父佈局
		GridPane gridPane = new GridPane();

		// 水平佈局,作為下方的選項巢狀入父佈局
		HBox hbox = new HBox();
		hbox.setPadding(new Insets(10)); // 填充
		hbox.setAlignment(Pos.CENTER); // 居中

		// 新增3個點選
		Button home = new Button("返回首頁");
		home.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即首頁視窗
				Start start = new Start();
				start.start(new Stage());
				// 關閉原本介面
				primaryStage.close();
			}
		});
		Button again = new Button("重新遊戲");
		again.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即遊戲視窗
				Game_3 game = new Game_3();
				game.start(new Stage());
				// 關閉開始介面
				primaryStage.close();
			}
		});
		Button look = new Button("檢視原圖");
		look.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent arg0) {
				// 開啟另一個視窗,即顯示原圖
				OnImage_3 OnImage = new OnImage_3();
				OnImage.start(new Stage());
			}
		});
		// 設定按鈕大小並居中
		home.setPrefSize(200, 50);
		again.setPrefSize(200, 50);
		look.setPrefSize(200, 50);
		// 設定控制元件之間的距離
		hbox.setSpacing(100);

		hbox.getChildren().addAll(home, again, look);

		// 遊戲部分
		/*
		 * 自定義的函式,產生逆序數為偶數的不重複陣列,依次作為圖片陣列的下標,例如: 2 0 1 3 4 5 6 7 ------>,此時m=8,變成如下即為正確:
		 * 0 1 2 3 4 5 4 7
		 */
		int[] n = random();

		Image image2 = new Image("application/2_2.jpg");

		for (int i = 0; i < 25; i++) {
			imageViews[i] = new ImageView(image2); // 初始化陣列
			imageViews[i].setOnMouseClicked(new myevent()); // 設定點選事件
		}
		for (int i = 0, k = 0; i <= 4; i++) {
			for (int j = 0; j <= 4; j++, k++) {
				imageViews[k].setViewport(new Rectangle2D(125 * j, 125 * i, 125, 125)); // 切割圖片分配給圖片陣列
			}
		}
		// 按照產生的隨機數將imageView陣列加入面板
		gridPane.add(imageViews[n[0]], 0, 0);
		gridPane.add(imageViews[n[1]], 1, 0);
		gridPane.add(imageViews[n[2]], 2, 0);
		gridPane.add(imageViews[n[3]], 3, 0);
		gridPane.add(imageViews[n[4]], 4, 0);
		gridPane.add(imageViews[n[5]], 0, 1);
		gridPane.add(imageViews[n[6]], 1, 1);
		gridPane.add(imageViews[n[7]], 2, 1);
		gridPane.add(imageViews[n[8]], 3, 1);
		gridPane.add(imageViews[n[9]], 4, 1);
		gridPane.add(imageViews[n[10]], 0, 2);
		gridPane.add(imageViews[n[11]], 1, 2);
		gridPane.add(imageViews[n[12]], 2, 2);
		gridPane.add(imageViews[n[13]], 3, 2);
		gridPane.add(imageViews[n[14]], 4, 2);
		gridPane.add(imageViews[n[15]], 0, 3);
		gridPane.add(imageViews[n[16]], 1, 3);
		gridPane.add(imageViews[n[17]], 2, 3);
		gridPane.add(imageViews[n[18]], 3, 3);
		gridPane.add(imageViews[n[19]], 4, 3);
		gridPane.add(imageViews[n[20]], 0, 4);
		gridPane.add(imageViews[n[21]], 1, 4);
		gridPane.add(imageViews[n[22]], 2, 4);
		gridPane.add(imageViews[n[23]], 3, 4);
		m = findnum(n); // 找出那個不在隨機數組裡面的數字

		Image image1 = new Image("application/3.jpg"); // 3.png為一個透明圖,放在空格子中
		imageViews[m].setImage(image1);
		gridPane.add(imageViews[m], 4, 4);
		gridPane.setGridLinesVisible(true);
		gridPane.setPrefWidth(800);
		gridPane.setPrefHeight(700);
		vBox.getChildren().add(gridPane);
		// 佈局巢狀,選項部分
		vBox.getChildren().add(hbox);

		// 標題欄圖示
		Image image = new Image("application/4.jpg");

		Scene scene = new Scene(vBox, 800, 800);
		scene.getStylesheets().add(getClass().getResource("Game.css").toExternalForm());
		primaryStage.getIcons().add(image);
		primaryStage.setTitle("智障拼圖");
		primaryStage.setScene(scene);
		primaryStage.setResizable(false);
		primaryStage.show();
	}

	public int[] random() { // 生成24個不重複的逆序數為偶數的數字,這樣拼圖才有結
		int[] ran = new int[24];
		while (iso(ran) == false) {
			ran = random_num();
		}
		return ran;

	}

	public int[] random_num() { // 生成24個不重複數
		int r[] = new int[24];
		Random random = new Random();
		for (int i = 0; i < 24; ++i) {
			r[i] = random.nextInt(25);
			for (int j = 0; j < i; ++j) {
				while (r[i] == r[j]) {
					i--;
					break;
				}
			}
		}
		return r;
	}

	// 判斷逆序數是否為偶數
	public boolean iso(int[] num) {
		int sum = 0;
		for (int i = 0; i <= 22; ++i) {
			for (int j = i; j <= 23; j++) {
				if (num[i] > num[j]) {
					sum++;
				}
			}
		}
		if ((sum % 2) == 0 && sum != 0) {
			return true;
		}

		return false;

	}

	// 點選事件的實現
	class myevent implements EventHandler<MouseEvent> {

		@Override
		public void handle(MouseEvent arg0) {

			ImageView img = (ImageView) arg0.getSource();
			double sx = img.getLayoutX();
			double sy = img.getLayoutY();
			double dispx = sx - imageViews[m].getLayoutX();
			double dispy = sy - imageViews[m].getLayoutY();
			if ((dispx == -125) && (dispy == 0)) { // 點選的空格左邊的格子
				swapimg(img, imageViews[m]); // 交換imageView
				if (issucc(imageViews)) { // 判斷是否拼成功
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}

			else if ((dispx == 0) && (dispy == -125)) { // 上面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 125) && (dispy == 0)) { // 右邊的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			} else if ((dispx == 0) && (dispy == 125)) { // 下面的格子
				swapimg(img, imageViews[m]);
				if (issucc(imageViews)) {
					Alert alert = new Alert(AlertType.WARNING, "恭喜你,拼圖成功!");
					alert.show();
				}
			}
		}

		// 交換兩個imageView的實現
		public void swapimg(ImageView i1, ImageView i2) {
			int row1 = GridPane.getRowIndex(i1);
			int colu1 = GridPane.getColumnIndex(i1);
			int row2 = GridPane.getRowIndex(i2);
			int colu2 = GridPane.getColumnIndex(i2);
			GridPane.setRowIndex(i1, row2);
			GridPane.setColumnIndex(i1, colu2);
			GridPane.setRowIndex(i2, row1);
			GridPane.setColumnIndex(i2, colu1);
		}
	}

	// 判斷是否拼圖成功
	public boolean issucc(ImageView[] imageViews) {
		for (int i = 0; i <= 24; ++i) {
			if (i != 3 * GridPane.getRowIndex(imageViews[i]) + GridPane.getColumnIndex(imageViews[i])) {
				return false;
			}
		}
		return true;
	}

	// 找出m
	public int findnum(int[] n) {
		for (int j = 0; j <= 24; ++j) {
			if ((j == n[0]) || (j == n[1]) || (j == n[2]) || (j == n[3]) || (j == n[4]) || (j == n[5]) || (j == n[6])
					|| (j == n[7]) || (j == n[8]) || (j == n[9]) || (j == n[10]) || (j == n[11]) || (j == n[12])
					|| (j == n[13]) || (j == n[14]) || (j == n[15]) || (j == n[16]) || (j == n[17]) || (j == n[18])
					|| (j == n[19]) || (j == n[20]) || (j == n[21]) || (j == n[22]) || (j == n[23])) {
			} else {
				return j;
			}
		}
		return -1;
	}

}

(5)簡單難度顯示原圖介面 

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
/**
*顯示原圖介面
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class OnImage_1 extends Application {

	@Override
	public void start(Stage primaryStage) {
		try {
			VBox vBox = new VBox();
			// 原圖
			Image image1 = new Image("application/2.jpg");
			double width = image1.getWidth();
			double higth = image1.getHeight();
			ImageView imageView = new ImageView(image1);
			vBox.getChildren().add(imageView);

			// 標題欄圖示
			Image image = new Image("application/4.jpg");

			Scene scene = new Scene(vBox, width, higth);
			scene.getStylesheets().add(getClass().getResource("Start.css").toExternalForm());
			primaryStage.getIcons().add(image);
			primaryStage.setTitle("智障拼圖");
			primaryStage.setScene(scene);
			primaryStage.setResizable(false);
			primaryStage.show();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

(6)困難難度顯示原圖介面 

import javafx.application.Application;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;

/**
*顯示原圖介面
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class OnImage_2 extends Application {

	@Override
	public void start(Stage primaryStage) {
		try {
			VBox vBox = new VBox();
			// 原圖
			Image image1 = new Image("application/2_1.jpg");
			double width = image1.getWidth();
			double higth = image1.getHeight();
			ImageView imageView = new ImageView(image1);
			vBox.getChildren().add(imageView);

			// 標題欄圖示
			Image image = new Image("application/4.jpg");

			Scene scene = new Scene(vBox, width, higth);
			scene.getStylesheets().add(getClass().getResource("Start.css").toExternalForm());
			primaryStage.getIcons().add(image);
			primaryStage.setTitle("智障拼圖");
			primaryStage.setScene(scene);
			primaryStage.setResizable(false);
			primaryStage.show();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

 

(7)地獄難度顯示原圖介面 

import javafx.application.Application;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;

/**
*顯示原圖介面
*作者:Mr. Yu
*2018年12月5日,下午5:40:51
 */
public class OnImage_3 extends Application {

	@Override
	public void start(Stage primaryStage) {
		try {
			VBox vBox = new VBox();
			// 原圖
			Image image1 = new Image("application/2_2.jpg");
			double width = image1.getWidth();
			double higth = image1.getHeight();
			ImageView imageView = new ImageView(image1);
			vBox.getChildren().add(imageView);

			// 標題欄圖示
			Image image = new Image("application/4.jpg");

			Scene scene = new Scene(vBox, width, higth);
			scene.getStylesheets().add(getClass().getResource("Start.css").toExternalForm());
			primaryStage.getIcons().add(image);
			primaryStage.setTitle("智障拼圖");
			primaryStage.setScene(scene);
			primaryStage.setResizable(false);
			primaryStage.show();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

有幾個點需要注意一下:(1)必須要裝JAVAFX外掛且JDK1.8或以上才可以執行,需要的可以找我提供內嵌了外掛的Eclipse安裝包

                                        (2)我的圖片是存放在資原始檔中,即在本包中,會被自動拷貝到bin目錄下,大家的圖片來源可以更換為本地圖片或網址圖片

 

(五)後續

現在這個程式還是很簡陋的,本來想美化一下介面,再完善一些功能,諸如倒計時,已走步數,精確提示,背景音樂播放,供玩家可選擇的拼圖圖片等等,但是想想自己那麼懶還是算了哈哈哈。