日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

JavaFx-----五子棋(单机版和对战版)

發(fā)布時間:2023/12/13 综合教程 39 生活家
生活随笔 收集整理的這篇文章主要介紹了 JavaFx-----五子棋(单机版和对战版) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一.項目介紹

使用 JavaFx + MySql + MyBatis 實現(xiàn)單機和網(wǎng)絡(luò)版五子棋對戰(zhàn).

二.功能介紹

1. 登錄

  -- 使用MyBatis和JDBC連接數(shù)據(jù)庫, 實現(xiàn)登錄功能

  -- 使用I/O流,實現(xiàn)本地文件記住密碼功能

2.注冊

  --使用MyBatis和JDBC連接數(shù)據(jù)庫, 實現(xiàn)注冊功能

  -- 注冊完密碼后,返回登錄界面,自動填充注冊的用戶名和密碼

3.網(wǎng)絡(luò)模式選擇

4.單機版

  -- 對戰(zhàn)

  -- 新局

  -- 悔棋

  -- 保存棋譜

  -- 打開棋譜

5.網(wǎng)絡(luò)版

  -- 顯示在線用戶

  -- 連接對戰(zhàn)

三. 項目源碼

package com.wn.main;

import java.net.InetAddress;
import java.net.UnknownHostException;

import com.wn.pojo.Global;
import com.wn.ui.LoginStage;

import javafx.application.Application;
import javafx.stage.Stage;

public class MainApplication extends Application {

	public static void main(String[] args) {
		launch(args);
	}
	@Override
	public void start(Stage primaryStage) throws Exception {
		//獲取當前用戶的本機IP地址
		InetAddress inetAddress = null;
		try {
			inetAddress = InetAddress.getLocalHost();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		//將本機ip存儲到全局變量中
		Global.myIp = inetAddress.getHostAddress();
		new LoginStage().show();		
	}
}
package com.wn.ui;

import com.wn.CommonUtils.DAOUtils;
import com.wn.CommonUtils.DataHanding;
import com.wn.dao.UserDAO;
import com.wn.dao.UserStatusDAO;
import com.wn.pojo.Global;
import com.wn.pojo.User;
import com.wn.pojo.UserStatus;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class LoginStage extends Stage implements EventHandler<ActionEvent> {
	private Button loginBtn;
	private Button registerBtn;
	private TextField account;
	private PasswordField password;
	private CheckBox checkBox;

	public LoginStage() {
		setTitle("五子棋-登錄");
		Pane pane = new Pane();
		Scene scene = new Scene(pane, 400, 250);
		setScene(scene);
		getIcons().add(new Image("Imgs/icon-2.jpg"));
		pane.setBackground(new Background(new BackgroundFill(Color.GAINSBORO, null, null)));
		// 設(shè)置窗口不可變
		setResizable(false);

		// 標題:用戶登錄
		Label title = new Label("用戶登錄");
		title.setFont(new Font("KaiTi", 30));
		title.setLayoutX(150);
		title.setLayoutY(30);
		// 賬戶標簽
		Label accountLabel = new Label("賬戶 : ");
		accountLabel.setFont(new Font("KaiTi", 20));
		accountLabel.setLayoutX(80);
		accountLabel.setLayoutY(90);
		// 賬戶輸入框
		account = new TextField();
		account.setLayoutX(150);
		account.setLayoutY(90);

		// 密碼標簽
		Label passwordLabel = new Label("密碼 : ");
		passwordLabel.setFont(new Font("KaiTi", 20));
		passwordLabel.setLayoutX(80);
		passwordLabel.setLayoutY(140);
		// 密碼輸入框
		password = new PasswordField();
		password.setLayoutX(150);
		password.setLayoutY(140);
		// 記住密碼
		checkBox = new CheckBox();
		checkBox.setLayoutX(80);
		checkBox.setLayoutY(180);
		Text text = new Text(100, 195,"記住密碼");
		text.setFont(new Font("KaiTi",15));
		// 登錄按鈕
		loginBtn = new Button("登	錄");
		loginBtn.setLayoutX(80);
		loginBtn.setLayoutY(210);
		loginBtn.setDefaultButton(true);
		loginBtn.setOnAction(this);
		// 注冊按鈕
		registerBtn = new Button("注	冊");
		registerBtn.setLayoutX(250);
		registerBtn.setLayoutY(210);
		registerBtn.setOnAction(this);
		// 把元素添加到面板
		pane.getChildren().addAll(title, accountLabel, account, passwordLabel, 
				password, loginBtn, registerBtn,checkBox,text);
		
		// 如果用戶剛注冊,則在登錄界面讀取用戶注冊的賬戶和密碼
		String content = null;
		if (Global.account != null && Global.password != null) {
			this.account.setText(Global.account);
			this.password.setText(Global.password);
			//讀取用戶上一次在本機登錄的賬戶和密碼
		}else if ((content=DataHanding.readLastAccount())!=null) {
			String[] strings = content.split(",");
			if (strings[strings.length-1].equals(Global.myIp)) {
				account.setText(strings[0]);
				password.setText(strings[1]);
			}
		}
	}
	
	
	
	public void login() {
		String accountText = account.getText();
		String passwordText = password.getText();
		Global.account = accountText;
		//用戶名或密碼不能為空
		if (accountText.equals("")||passwordText.equals("")) {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("用戶名或密碼不能為空");
			alert.show();
			return;
		}
		//獲取用戶當前登錄狀態(tài),如果已登錄,不能重復(fù)登錄
		UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
		UserStatus status = statusDAO.selectInfoByAccount(accountText);
		if (status.getStatus() == 1) {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("當前用戶已在線,不能重復(fù)登錄");
			alert.show();
			return;
		}
		// 獲取UserDAO的實現(xiàn)類
		UserDAO userDAO = DAOUtils.getMapper(UserDAO.class);
		// 根據(jù)用戶輸入的account獲得User對象
		User user = userDAO.getByAccount(accountText);
		if (user != null && user.getPassword().equals(passwordText)) {
			//登錄成功,判斷用戶是否選擇記住密碼
			if (checkBox.isSelected()) {
				//用戶選擇記住密碼,調(diào)用記住密碼方法
				DataHanding.rememberLastAccount(accountText, passwordText,Global.myIp);
			}
			//更新用戶狀態(tài)為在線狀態(tài)
			statusDAO.updateStatusByAccount(accountText,Global.myIp, 1);
			// 已設(shè)置自動提交事務(wù)
			// 打開游戲模式選擇界面
			new ModeChooseStage().show();
			this.close();
		} else {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("用戶名或密碼錯誤 ,登錄失敗");
			alert.showAndWait();
		}
	}
	
	

	@Override
	public void handle(ActionEvent event) {
		//獲取用戶點擊的按鈕
		Button btn = (Button) event.getSource();
		String text = btn.getText();
		switch (text) {
		case "登	錄":
			login();
			break;
		case "注	冊":
			new RegisterStage().show();
			this.close();
			break;
		}
	}
}

  

package com.wn.ui;

import com.wn.CommonUtils.DAOUtils;
import com.wn.CommonUtils.DataHanding;
import com.wn.dao.UserDAO;
import com.wn.dao.UserStatusDAO;
import com.wn.pojo.Global;
import com.wn.pojo.User;
import com.wn.pojo.UserStatus;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class LoginStage extends Stage implements EventHandler<ActionEvent> {
	private Button loginBtn;
	private Button registerBtn;
	private TextField account;
	private PasswordField password;
	private CheckBox checkBox;

	public LoginStage() {
		setTitle("五子棋-登錄");
		Pane pane = new Pane();
		Scene scene = new Scene(pane, 400, 250);
		setScene(scene);
		getIcons().add(new Image("Imgs/icon-2.jpg"));
		pane.setBackground(new Background(new BackgroundFill(Color.GAINSBORO, null, null)));
		// 設(shè)置窗口不可變
		setResizable(false);

		// 標題:用戶登錄
		Label title = new Label("用戶登錄");
		title.setFont(new Font("KaiTi", 30));
		title.setLayoutX(150);
		title.setLayoutY(30);
		// 賬戶標簽
		Label accountLabel = new Label("賬戶 : ");
		accountLabel.setFont(new Font("KaiTi", 20));
		accountLabel.setLayoutX(80);
		accountLabel.setLayoutY(90);
		// 賬戶輸入框
		account = new TextField();
		account.setLayoutX(150);
		account.setLayoutY(90);

		// 密碼標簽
		Label passwordLabel = new Label("密碼 : ");
		passwordLabel.setFont(new Font("KaiTi", 20));
		passwordLabel.setLayoutX(80);
		passwordLabel.setLayoutY(140);
		// 密碼輸入框
		password = new PasswordField();
		password.setLayoutX(150);
		password.setLayoutY(140);
		// 記住密碼
		checkBox = new CheckBox();
		checkBox.setLayoutX(80);
		checkBox.setLayoutY(180);
		Text text = new Text(100, 195,"記住密碼");
		text.setFont(new Font("KaiTi",15));
		// 登錄按鈕
		loginBtn = new Button("登	錄");
		loginBtn.setLayoutX(80);
		loginBtn.setLayoutY(210);
		loginBtn.setDefaultButton(true);
		loginBtn.setOnAction(this);
		// 注冊按鈕
		registerBtn = new Button("注	冊");
		registerBtn.setLayoutX(250);
		registerBtn.setLayoutY(210);
		registerBtn.setOnAction(this);
		// 把元素添加到面板
		pane.getChildren().addAll(title, accountLabel, account, passwordLabel, 
				password, loginBtn, registerBtn,checkBox,text);
		
		// 如果用戶剛注冊,則在登錄界面讀取用戶注冊的賬戶和密碼
		String content = null;
		if (Global.account != null && Global.password != null) {
			this.account.setText(Global.account);
			this.password.setText(Global.password);
			//讀取用戶上一次在本機登錄的賬戶和密碼
		}else if ((content=DataHanding.readLastAccount())!=null) {
			String[] strings = content.split(",");
			if (strings[strings.length-1].equals(Global.myIp)) {
				account.setText(strings[0]);
				password.setText(strings[1]);
			}
		}
	}
	
	
	
	public void login() {
		String accountText = account.getText();
		String passwordText = password.getText();
		Global.account = accountText;
		//用戶名或密碼不能為空
		if (accountText.equals("")||passwordText.equals("")) {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("用戶名或密碼不能為空");
			alert.show();
			return;
		}
		//獲取用戶當前登錄狀態(tài),如果已登錄,不能重復(fù)登錄
		UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
		UserStatus status = statusDAO.selectInfoByAccount(accountText);
		if (status.getStatus() == 1) {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("當前用戶已在線,不能重復(fù)登錄");
			alert.show();
			return;
		}
		// 獲取UserDAO的實現(xiàn)類
		UserDAO userDAO = DAOUtils.getMapper(UserDAO.class);
		// 根據(jù)用戶輸入的account獲得User對象
		User user = userDAO.getByAccount(accountText);
		if (user != null && user.getPassword().equals(passwordText)) {
			//登錄成功,判斷用戶是否選擇記住密碼
			if (checkBox.isSelected()) {
				//用戶選擇記住密碼,調(diào)用記住密碼方法
				DataHanding.rememberLastAccount(accountText, passwordText,Global.myIp);
			}
			//更新用戶狀態(tài)為在線狀態(tài)
			statusDAO.updateStatusByAccount(accountText,Global.myIp, 1);
			// 已設(shè)置自動提交事務(wù)
			// 打開游戲模式選擇界面
			new ModeChooseStage().show();
			this.close();
		} else {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("用戶名或密碼錯誤 ,登錄失敗");
			alert.showAndWait();
		}
	}
	
	

	@Override
	public void handle(ActionEvent event) {
		//獲取用戶點擊的按鈕
		Button btn = (Button) event.getSource();
		String text = btn.getText();
		switch (text) {
		case "登	錄":
			login();
			break;
		case "注	冊":
			new RegisterStage().show();
			this.close();
			break;
		}
	}
}

  

package com.wn.ui;

import com.wn.CommonUtils.DAOUtils;
import com.wn.dao.UserStatusDAO;
import com.wn.pojo.ChessMode;
import com.wn.pojo.Global;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class ModeChooseStage extends Stage implements EventHandler<ActionEvent> {
	Pane pane;
	public ModeChooseStage() {
		setTitle("五林大會");
		pane = new Pane();
		Scene scene = new Scene(pane,460,260);
		setScene(scene);
		getIcons().add(new Image("Imgs/icon-2.jpg"));
		Image image = new Image("Imgs/Gobang.jpg",480,280,false,true,true);
		ImageView imageView = new ImageView(image); 
		pane.getChildren().add(imageView);
		pane.setBackground(new Background(
				new BackgroundFill(Color.DARKOLIVEGREEN, null, null)));
		// 設(shè)置窗口不可變
		setResizable(false);
		
		setOnCloseRequest(new EventHandler<WindowEvent>() {

			@Override
			public void handle(WindowEvent event) {
				UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
				statusDAO.setStatusByAccount(Global.account, 0);
			}
		});
		
		Label title = new Label("選擇游戲模式");
		title.setFont(new Font("KaiTi", 30));
		title.setLayoutX(155);
		title.setLayoutY(80);
		
		//添加單機版和網(wǎng)絡(luò)部按鈕
		Button buttonOnline = new Button("網(wǎng)絡(luò)版");
		buttonOnline.setFont(new Font("KaiTi",20));
		buttonOnline.setPrefSize(100, 60);
		buttonOnline.setLayoutX(280);
		buttonOnline.setLayoutY(140);
		buttonOnline.setOnAction(this);
		
		Button buttonSingle = new Button("單機版");
		buttonSingle.setFont(new Font("KaiTi",20));
		buttonSingle.setPrefSize(100, 60);
		buttonSingle.setLayoutX(80);
		buttonSingle.setLayoutY(140);
		buttonSingle.setOnAction(this);
		//將按鈕添加進面板
		pane.getChildren().addAll(title,buttonOnline,buttonSingle);
		
	}
	
	
	/**
	 * 	在線模式
	 * @author Dracarys
	 */
	public void playOnineVersion() {
		new OnlineConfigStage().show();
		this.close();
		Global.mode = ChessMode.NETWORK;
	}
	
	/**
	 *	單機版按鈕及單機版游戲事件 
	 * @author Dracarys
	 * @param pane
	 */
	public void playSingleVersion() {
		try {
			new GameStage().show();
			Global.mode = ChessMode.SINGLE;
			this.close();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}	
		
	}

	@Override
	public void handle(ActionEvent event) {
		Button btn = (Button)event.getSource();
		switch (btn.getText()) {
		case "單機版":
			playSingleVersion();
			break;

		case "網(wǎng)絡(luò)版":
			playOnineVersion();
			break;
		}
		
	}

}

  

package com.wn.ui;

import java.util.List;

import com.wn.CommonUtils.DAOUtils;
import com.wn.CommonUtils.NetUtils;
import com.wn.CommonUtils.ReceiveThread;
import com.wn.dao.UserStatusDAO;
import com.wn.pojo.ConnectionMessage;
import com.wn.pojo.Global;
import com.wn.pojo.UserStatus;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class OnlineConfigStage extends Stage implements EventHandler<ActionEvent> {
	private Pane pane;          //舞臺面板
	private TextField myPort;	//本機端口
	private TextField conIp;	//連接ip
	private TextField conPort;	//連接端口
	private List<UserStatus> list;	//在線用戶列表
	
	public OnlineConfigStage(){
		setTitle("網(wǎng)絡(luò)連接設(shè)置");
		pane = new Pane();
		Scene scene = new Scene(pane,600,400);
		setScene(scene);
		getIcons().add(new Image("Imgs/icon-2.jpg"));
		pane.setBackground(new Background(new BackgroundFill(Color.GAINSBORO, null, null)));
		// 設(shè)置窗口不可變
		setResizable(false);
		addElement();
		getOnlineUser();
		
		//當用戶退出程序時,將用戶的狀態(tài)設(shè)置為下線
		setOnCloseRequest(new EventHandler<WindowEvent>() {

			@Override
			public void handle(WindowEvent event) {
				UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
				statusDAO.setStatusByAccount(Global.account, 0);
			}
		});
		
	}
	
	private void addTipsInfo() {
		//在線玩家標題提示
		Label title = new Label("當前在線玩家");
		title.setFont(new Font("KaiTi", 30));
		title.setLayoutX(350);
		title.setLayoutY(30);
		pane.getChildren().add(title);
		//在線用戶信息行
		String[] tipsInfo = {"用戶名","連接IP","連接PORT"};
		for (int i = 0; i < tipsInfo.length; i++) {
			Label Lable = new Label(tipsInfo[i]);
			Lable.setFont(new Font("KaiTi", 20));
			Lable.setLayoutX(280+100*i);
			Lable.setLayoutY(80);
			pane.getChildren().add(Lable);
		}
	}
	
	private void addElement() {
		//網(wǎng)絡(luò)連接設(shè)置標題提示
		Label title = new Label("網(wǎng)絡(luò)連接設(shè)置");
		title.setFont(new Font("KaiTi", 30));
		title.setLayoutX(50);
		title.setLayoutY(30);
		//連接地址文本提示
		Label myPortLable = new Label("本機端口");
		myPortLable.setFont(new Font("KaiTi", 20));
		myPortLable.setLayoutX(60);
		myPortLable.setLayoutY(90);
		//添加本機端口輸入框
		myPort = new TextField();
		myPort.setLayoutX(60);
		myPort.setLayoutY(120);
		myPort.setText("6666"); //測試port
		//連接端口文本提示
		Label conIPLable = new Label("連接IP");
		conIPLable.setFont(new Font("KaiTi", 20));
		conIPLable.setLayoutX(60);
		conIPLable.setLayoutY(160);
		//添加連接IP輸入框
		conIp = new TextField();
		conIp.setLayoutX(60);
		conIp.setLayoutY(190);
		conIp.setText("192.172.4.8"); //測試ip
		//連接端口文本提示
		Label conPortLable = new Label("連接端口");
		conPortLable.setFont(new Font("KaiTi", 20));
		conPortLable.setLayoutX(60);
		conPortLable.setLayoutY(230);
		//添加連接PORT輸入框
		conPort = new TextField();
		conPort.setLayoutX(60);
		conPort.setLayoutY(260);
		conPort.setText("6666"); //測試port
		
		//添加確定和取消按鈕
		Button conBtn = new Button("連	接");
		conBtn.setPrefSize(150, 30);
		conBtn.setLayoutX(60);
		conBtn.setLayoutY(320);
		conBtn.setOnAction(this);
		
		Button canBtn = new Button("取	消");
		canBtn.setPrefSize(150, 25);
		canBtn.setLayoutX(60);
		canBtn.setLayoutY(360);
		canBtn.setOnAction(this);
		
		pane.getChildren().addAll(title,myPortLable,myPort,conIPLable,conIp,conPortLable,conPort,conBtn,canBtn);
	}
	
		
	
	private void getOnlineUser() {
		//獲取UserStatusDAO實現(xiàn)類
		UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
		//獲取在線用戶列表
		list = statusDAO.selectInfoByStatus(1);
		if (list.size()<=1) {
			return;
		}
		addTipsInfo();
		int i = 0;
		for (UserStatus userStatus : list) {
			if (!userStatus.getAccount().equals(Global.account)) {
				//添加用戶名信息
				Label accountLable = new Label(userStatus.getAccount());
				accountLable.setFont(new Font("KaiTi", 20));
				accountLable.setLayoutX(290);
				accountLable.setLayoutY(120+60*i);
				
				//添加ip信息
				Label ipLable = new Label(userStatus.getIp());
				ipLable.setFont(new Font("KaiTi", 20));
				ipLable.setLayoutX(360);
				ipLable.setLayoutY(120+60*i);
				
				//添加port信息
				Label portLable = new Label(userStatus.getPort()+"");
				portLable.setFont(new Font("KaiTi", 20));
				portLable.setLayoutX(500);
				portLable.setLayoutY(120+60*i);
				pane.getChildren().addAll(accountLable,ipLable,portLable);
				i++;
			}
		}
	}
	
	public void connect(){
		//當網(wǎng)絡(luò)連接信息未填寫時,彈窗提醒
		if (myPort.getText().equals("") || conIp.getText().equals("") || conPort.getText().equals("")) {
			Alert alert = new Alert(AlertType.INFORMATION,"網(wǎng)絡(luò)連接信息不能為空");
			alert.initOwner(this);
			alert.showAndWait();
			return;
		}
		//如果沒有在線用戶時,無法正常連接
		if (list.size()<=1) {
			Alert alert = new Alert(AlertType.INFORMATION,"當前無在線用戶,無法進行連接");
			alert.initOwner(this);
			alert.showAndWait();
			return;
		}
		
		//嘗試將用戶輸入的端口信息轉(zhuǎn)為int型
		try {
			Global.myPort = Integer.parseInt(myPort.getText());
			Global.oppoIp = conIp.getText();
			Global.oppoPort = Integer.parseInt(conPort.getText());
		} catch (NumberFormatException e1) {
			e1.printStackTrace();
			return;
		}
		try {
			//啟動線程,接收客戶端連接
			ReceiveThread receiveThread = new ReceiveThread();
			Thread thread = new Thread(receiveThread);
			thread.start();
			new GameStage().show();
			//將用戶輸入的本機端口保存到數(shù)據(jù)庫
			UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
			statusDAO.updatePortByAccount(Global.account, Global.myPort);
			//向服務(wù)端發(fā)送連接請求信息,連接信息中包含客戶端的用戶
			NetUtils.sendMessage(new ConnectionMessage(Global.account));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.close();
	}

	@Override
	public void handle(ActionEvent event) {
		Button btn = (Button)event.getSource();
		switch (btn.getText()) {
		case "連	接":
			connect();
			break;
		case "取	消":
			new ModeChooseStage().show();
			this.close();
			break;
		}
	}
}

  

package com.wn.ui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;

import com.wn.CommonUtils.DAOUtils;
import com.wn.CommonUtils.NetUtils;
import com.wn.dao.UserStatusDAO;
import com.wn.pojo.ButtonMessage;
import com.wn.pojo.ChessMessage;
import com.wn.pojo.ChessMode;
import com.wn.pojo.ConnectionMessage;
import com.wn.pojo.Global;
import com.wn.pojo.Message;
import com.wn.pojo.MessageTimes;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class GameStage extends Stage implements EventHandler<ActionEvent> {
	
	private List<Circle> chessList = new ArrayList<Circle>(); 
	private boolean isBlack = true; //判斷棋子是否是黑色
	private boolean gameOver = false; //判斷游戲是否結(jié)束 true游戲結(jié)束,false代表可以下棋
	private int topMargin = 50;//上間距
	private int leftMargin = 350;//上間距
	private int gap = 50; //內(nèi)間距
	private int chessWidth = 1400; //棋盤寬
	private int chessHeight = 830; //棋盤高
	private int size = 15; //棋盤線條數(shù)
	private int buttonWidth = 80; //按鈕寬
	private int buttonLength = 40; //按鈕高
	private int cicreRadius = 18; //棋子半徑
	private int i = 0; //打開棋譜記錄當前是第幾手棋
	private boolean canPlay = false;  //定義網(wǎng)絡(luò)模式下,當前是否能下棋
	
	Pane pane;
		
	public GameStage() throws InterruptedException {
		//設(shè)置窗口不可改變
//		setResizable(false);
		//創(chuàng)建面板對象
		pane = new Pane();
		//創(chuàng)建場景對象
		Scene scene = new Scene(pane,chessWidth,chessHeight);
		//將場景放進舞臺
		setScene(scene);
		getIcons().add(new Image("Imgs/icon-2.jpg"));
		Image image = new Image("Imgs/background.jpg",1400,830,false,true,true);
		ImageView imageView = new ImageView(image); 
		pane.getChildren().add(imageView);
		setTitle("五子棋");
		drawLine();
		addButton();
		Global.gameStage = this;
		playChess();
		
		//當用戶退出程序時,將用戶的狀態(tài)設(shè)置為下線
		setOnCloseRequest(new EventHandler<WindowEvent>() {

			@Override
			public void handle(WindowEvent event) {
				exitGame();
			}
		});
	}
	
	/**
	 * 	根據(jù)接收到的Message對象,更新棋子信息
	 * @author Dracarys
	 */
	public void updateUI(Message message) {
		if (message instanceof ConnectionMessage) {
			ConnectionMessage conMessage = (ConnectionMessage)message;
			if (conMessage.getClientUser()!=null) {
				//有客戶端連接時,彈窗提醒
				Alert alert = new Alert(AlertType.CONFIRMATION,conMessage.getClientUser()+"已進入戰(zhàn)斗!!");
				alert.initOwner(this);
				alert.show();
			}
		//接收到的消息為棋子信息消息
		}else if (message instanceof ChessMessage) {
			ChessMessage chessMessage = (ChessMessage)message;
			double x = chessMessage.getX();
			double y = chessMessage.getY();
			double pieceX = x * gap + leftMargin;
			double pieceY = y * gap + topMargin;
			dropPiece(pieceX, pieceY);
			//接收到消息之后將標簽改完false
			canPlay = false;
			return;
		//接收到的消息為按鈕信息消息
		}else if (message instanceof ButtonMessage) {
			ButtonMessage btnMessage = (ButtonMessage)message;
			String btnName = btnMessage.getBtnName();
			switch (btnName) {
			case "新	局":
				//接收到點擊新局按鈕的第一次消息
				if (btnMessage.getTimes().equals(MessageTimes.FIRST)) {
					//彈窗提醒,讓接收方選擇是否同意開啟新局
					Alert alert = new Alert(AlertType.CONFIRMATION,"對方想開啟新局");
					alert.initOwner(this);
					alert.showAndWait();
					//如果用戶選擇同意開啟新局,則開啟新局
					if (alert.getResult() == ButtonType.OK) {
						startGame();
					//然后用戶不同意開啟新局,將按鈕消息的同意情況更改為false
					}else {
						//不同意,更改isAgree為false
						btnMessage.setAgree(false);
					}
					//向新局發(fā)起方發(fā)送消息
					btnMessage.setTimes(MessageTimes.SECOND);
					NetUtils.sendMessage(btnMessage);
				}else if (btnMessage.getTimes().equals(MessageTimes.SECOND)) {
					Alert alert = new Alert(AlertType.INFORMATION);
					//對方不同意開啟新局
					if (!btnMessage.isAgree()) {
						alert.setContentText("對方不同意開啟新局");
						alert.initOwner(this);
						alert.showAndWait();
					}else {
						alert.setContentText("對方同意開啟新局");
						alert.initOwner(this);
						alert.showAndWait();
						startGame();
					}
				}
				break;
			case "悔	棋":
				//第一次接收到悔棋消息時,讓接收方選擇是否悔棋
				if (btnMessage.getTimes().equals(MessageTimes.FIRST)) {
					//彈窗提醒,通過同意,就開啟新局
					Alert alert = new Alert(AlertType.CONFIRMATION,"對方想悔棋");
					alert.showAndWait();
					//如果用戶選擇同意悔棋,則直接悔棋,并發(fā)送消息
					if (alert.getResult() == ButtonType.OK) {
						regretChess();
						canPlay = false;
					//然后用戶不同意悔棋,將按鈕消息的同意情況更改為false
					}else {
						//不同意,更改isAgree為false
						btnMessage.setAgree(false);
					}
					//向悔棋發(fā)起方發(fā)送消息
					btnMessage.setTimes(MessageTimes.SECOND);
					NetUtils.sendMessage(btnMessage);
				}else if (btnMessage.getTimes().equals(MessageTimes.SECOND)) {
					Alert alert = new Alert(AlertType.INFORMATION);
					//對方不同意悔棋
					if (!btnMessage.isAgree()) {
						alert.setContentText("對方不同意悔棋");
						alert.show();
					}else {
						regretChess();
						canPlay = false;
						Global.regretTimes = 1;
					}
				}
				break;
			}
		}
	}
	
	
	/**
	 *	保存棋譜 
	 * @author Dracarys
	 * @param pane
	 */
	public void saveChessRecord() {
		if (!gameOver) {
			return;
		}
		//創(chuàng)建打開文件彈窗對象
		FileChooser fileChooser = new FileChooser();
		//設(shè)置彈窗標題
		fileChooser.setTitle("保存棋譜");
		//設(shè)置默認目錄
		fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
		//設(shè)置文件后綴
		fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("csv", "*.csv"));
		//打開文件保存對話框
		File file = fileChooser.showSaveDialog(this);
		//點擊取消,則文件為空,停止保存
		if (file == null) {
			return;
		}
		try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
			for (Circle chess : chessList) {
				bw.write(chess.getCenterX()+","+chess.getCenterY()+","+chess.getFill());
				bw.newLine();
			}
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setContentText("保存棋譜成功");
			alert.show();
		} catch (Exception e) {
		}
	}
	/**
	 *	打開棋譜 
	 * @author Dracarys
	 * @param pane
	 */
	public void openChessScore() {
		//打開棋譜僅在單機版有效,網(wǎng)絡(luò)版點擊彈框提醒
		if (Global.mode.equals(ChessMode.NETWORK)) {
			Alert alert = new Alert(AlertType.INFORMATION,"該功能僅在單機版有效");
			alert.showAndWait();
			return;
		}
		//創(chuàng)建打開文件彈窗對象
		FileChooser fc = new FileChooser();
		//設(shè)置對象標題
		fc.setTitle("打開棋譜");
		//設(shè)置打開的初始路徑
		fc.setInitialDirectory(new File(System.getProperty("user.home")));
		//設(shè)置打開的文件默認后綴
		fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("csv", "*.csv"));
		//將選擇的文件賦值給file對象
		File file = fc.showOpenDialog(this);
		//如果文件為空則不繼續(xù)打開
		if (file == null) {
			return;
		}
		//打開棋譜時情況棋子集合和棋盤上的棋子
		chessList.clear();
		pane.getChildren().removeIf(c-> c instanceof Circle);
		i = 0;
		//創(chuàng)建緩沖流,讀取棋譜文件
		try (BufferedReader br = new BufferedReader(new FileReader(file)) ) {
			String content;
			while ((content = br.readLine())!=null) {
				String[] list = content.split(",");
				//根據(jù)文件棋子信息創(chuàng)建棋子
				Circle chess = new Circle(Double.parseDouble(list[0]), Double.parseDouble(list[1]), cicreRadius,Color.web(list[2]));
				//將棋子添加進集合
				chessList.add(chess);
			}
		} catch (Exception e) {
		}
		//產(chǎn)生三個按鈕控制棋譜讀取
		String[] list = {"<",">","x"};
		for (int i = 0; i < list.length; i++) {
			Button btn = new Button(list[i]);
			btn.setPrefSize(30, 30);
			btn.setLayoutX(1060);
			btn.setLayoutY(300+60*i);
			btn.setOnAction(this);
			pane.getChildren().add(btn);
		}
	}
	
	/**
	 *	退出游戲 
	 * @author Dracarys
	 * @param pane
	 */
	public void exitGame() {
		Alert alert = new Alert(AlertType.CONFIRMATION);
		alert.setTitle("退出游戲確認");
		alert.setHeaderText("點擊確認按鈕將退出游戲程序");
		alert.setContentText("您確認退出嗎?");
		alert.showAndWait();
		if (alert.getResult() == ButtonType.OK) {
			if (Global.mode.equals(ChessMode.SINGLE)) {
				System.exit(0);
			}else {
				UserStatusDAO statusDAO = DAOUtils.getMapper(UserStatusDAO.class);
				statusDAO.setStatusByAccount(Global.account, 0);
				System.exit(0);
			}
		}
	}
	/**
	 *	悔棋
	 * @author Dracarys
	 */
	public void regretChess() {
		if (chessList.size()>=1&&gameOver == false) {
			chessList.remove(chessList.size()-1);
			pane.getChildren().remove(pane.getChildren().size()-1);
			isBlack = !isBlack;
		}		
	}
	
	/**
	 *	開始游戲事件
	 * @author Dracarys
	 * @param pane
	 */
	public void startGame() {
//		if (!gameOver) {
//			Alert alert = new Alert(AlertType.INFORMATION,"游戲還未結(jié)束不能開始新局");
//			alert.showAndWait();
//			return;
//		}
		gameOver = false;
		isBlack = true;
		chessList.clear();
		pane.getChildren().removeIf(c -> c instanceof Circle);	
	}
	
	
	/**
	 * 	添加棋盤線
	 * @author Dracarys
	 * @param pane
	 */
	public void drawLine() {
		//棋盤700*700,橫豎14條線,每條先間隔50
		//第一條橫線起點(350,50),y起點(1050,50);第一條豎線x起點(350,50),y起點(350,650)
		//第二條橫線x起點(350,100),y起點(1050,100);第二條豎線x起點(1050,50),y起點(1050,650)
		for (int i = 0; i < size; i++) {
			//橫線
			Line line1 = new Line(leftMargin, topMargin+i*gap, leftMargin+50*14, topMargin+i*gap);
			//豎線
			Line line2 = new Line(leftMargin+i*gap, topMargin, leftMargin+i*gap, topMargin+50*14);
			pane.getChildren().add(line1);
			pane.getChildren().add(line2);
		}
		
	}
	//添加按鈕
	public void addButton() {
		String[] btnList = {"新	局","保存棋譜","打開棋譜","悔	棋","退	出"};
		for (int i = 0; i < btnList.length; i++) {
			Button button = new Button(btnList[i]);
			button.setPrefSize(buttonWidth, buttonLength);
			button.setLayoutX(leftMargin+75*i+buttonWidth*i);
			button.setLayoutY(size*topMargin+20);
			button.setOnAction(this);
			pane.getChildren().add(button);
		}
	}
	
	/**
	 * 	在鼠標點擊的位置落子
	 * @author Dracarys
	 * @param pane
	 */
	public void playChess() {
		pane.setOnMouseClicked(e -> {
			//網(wǎng)絡(luò)版:判斷用戶是否已發(fā)送棋子消息,如果已發(fā)送
			if (canPlay) {
				return;
			}
			if (gameOver) {
				return;
			}
			double x = e.getX(); //獲取用戶鼠標點擊的坐標x值
			double y = e.getY(); //獲取用戶鼠標點擊的坐標y值
			//左上頂點坐標(50,50),棋子半徑為18,邊界為坐標-棋子半徑
			//右下頂點坐標(750,750),棋子半徑為18,邊界為坐標+棋子半徑
			if (x < leftMargin - cicreRadius || x > chessWidth - leftMargin + cicreRadius) {
				return;
			}
			if (y < topMargin - cicreRadius || y > 800 - topMargin + cicreRadius) {
					 //50-18 = 32                         
				return;
			}
			//將鼠標的坐標x和y都換算成(1,1)->(14,14)范圍
			double xIndex = Math.round(((x - leftMargin) / gap));
			double yIndex = Math.round(((y - topMargin) / gap));
			//判斷當前鼠標點的位置是否存在棋子
			double pieceX = xIndex * gap + leftMargin;
			double pieceY = yIndex * gap + topMargin;
			if (hasPiece(pieceX, pieceY)) {
				return;
			}
			//落棋子
			dropPiece(pieceX,pieceY);
			//創(chuàng)建棋子消息對象
			if (Global.mode.equals(ChessMode.NETWORK)) {
				ChessMessage message = new ChessMessage(xIndex,yIndex);
				//發(fā)送棋子消息對象
				NetUtils.sendMessage(message);
				canPlay = true;
			}
		});	
	}
	
	public void dropPiece(double x,double y) {
		Circle circle = new Circle();
		//設(shè)置棋子落子的坐標
		circle.setCenterX(x);
		circle.setCenterY(y);
		
		circle.setRadius(cicreRadius);
		if (isBlack) {
			circle.setFill(Color.BLACK);
		} else {
			circle.setFill(Color.WHITE);
		}
		pane.getChildren().add(circle);
		isBlack = !isBlack;
		Circle chess = new Circle(x, y,cicreRadius, isBlack ? Color.BLACK : Color.WHITE);
		chessList.add(chess);
		//判斷游戲輸贏
		if (isWin(chess)) {
			Alert alert = new Alert(AlertType.INFORMATION);
			alert.setTitle("游戲結(jié)束");
			alert.setHeaderText("游戲結(jié)果");
			alert.setContentText(isBlack ? "白棋勝" : "黑棋勝");
			alert.show();
			gameOver = true;
		}
	}
	
	 /** 	判斷當前坐標位置是否有棋子
	 * @author Dracarys
	 * @param x
	 * @param y
	 * @return
	 */
	private boolean hasPiece(double x,double y) {
		//遍歷數(shù)組
		for (int i = 0; i < chessList.size(); i++) {
			Circle c = chessList.get(i);
			if (c.getCenterX() == x && c.getCenterY() == y) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 	判斷是否勝利
	 * @author Dracarys
	 * @param chess
	 * @return
	 */
	private boolean isWin(Circle chess) {
		int count = 1;
		//判斷x軸向左邊判斷另外4個位置棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessLeft = new Circle(chess.getCenterX()-i*gap, 
					chess.getCenterY(),cicreRadius,chess.getFill());
			if (contain(chessLeft)) {
				count++;
			}else {
				break;
			}
		}
		//判斷x軸向右邊判斷另外4個位子棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessRight = new Circle(chess.getCenterX()+i*gap, 
					chess.getCenterY(),cicreRadius,chess.getFill());
			if (contain(chessRight)) {
				count++;
			}else {
				break;
			}
		}
		if (count>=5) {
			return true;
		}
		count = 1;
		//判讀y軸向上4個位置的棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessTop = new Circle(chess.getCenterX(),
					chess.getCenterY()-i*gap,cicreRadius,chess.getFill());
			if (contain(chessTop)) {
				count++;
			}else {
				break;
			}
		}
		//判讀y軸向下4個位置的棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessDown = new Circle(chess.getCenterX(), 
					chess.getCenterY()+i*gap,cicreRadius,chess.getFill());
			if (contain(chessDown)) {
				count++;
			}else {
				break;
			}
		}
		if (count>=5) {
			return true;
		}
		count = 1;
		//判讀左斜線邊4個棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessTopLeft = new Circle(chess.getCenterX()-i*gap, 
					chess.getCenterY()-i*gap,cicreRadius,chess.getFill());
			if (contain(chessTopLeft)) {
				count++;
			}else {
				break;
			}
		}
		//判讀左斜線邊4個棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessTopRight = new Circle(chess.getCenterX()+i*gap, 
					chess.getCenterY()+i*gap,cicreRadius,chess.getFill());
			if (contain(chessTopRight)) {
				count++;
			}else {
				break;
			}
		}
		if (count>=5) {
			return true;
		}
		count = 1;
		//判讀右斜線邊4個棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessDownLeft = new Circle(chess.getCenterX()+i*gap, 
					chess.getCenterY()-i*gap,cicreRadius,chess.getFill());
			if (contain(chessDownLeft)) {
				count++;
			}else {
				break;
			}
		}
		//判讀右斜線邊4個棋子是否同色
		for (int i = 1; i < 5; i++) {
			Circle chessDownRight = new Circle(chess.getCenterX()-i*gap, 
					chess.getCenterY()+i*gap,cicreRadius,chess.getFill());
			if (contain(chessDownRight)) {
				count++;
			}else {
				break;
			}
		}
		if (count>=5) {
			return true;
		}
		return false;
	}
	/**
	 * 	判斷棋子集合中是否包含當前棋子
	 * @author Dracarys
	 * @param chess
	 * @return
	 */
	public boolean contain(Circle chess) {
		for (Circle circle : chessList) {
			if (circle.getCenterX() == chess.getCenterX() && circle.getCenterY()==chess.getCenterY()&&circle.getFill().equals(chess.getFill())) {
				return true;
			}		
		}
	return false;		
	}
	/**
	 * 	重寫用戶點擊按鈕的方法
	 */
	@Override
	public void handle(ActionEvent event) {
		Button source = (Button) event.getSource();
		String text = source.getText();
		switch (text) {
		case "新	局":
			if (Global.mode.equals(ChessMode.SINGLE)) {
				startGame();
			}else {
				ButtonMessage btnMessage = new ButtonMessage(text,true,MessageTimes.FIRST);
				NetUtils.sendMessage(btnMessage);
			}
			break;
		case "保存棋譜":
			saveChessRecord();
			break;
		case "打開棋譜":
			openChessScore();
			break;
		case "悔	棋":
			if (gameOver) {
				return;
			}
			if (chessList.isEmpty()) {
				return;
			}
			if (Global.regretTimes>=1) {
				Alert alert = new Alert(AlertType.INFORMATION,"已經(jīng)悔悔過棋, 不能再次悔棋");
				alert.initOwner(this);
				alert.show();
				return;
			}
			
			if (!canPlay) {
				Alert alert = new Alert(AlertType.INFORMATION,"不能悔棋");
				alert.initOwner(this);
				alert.show();
				return;
			}
			if (Global.mode.equals(ChessMode.SINGLE)) {
				regretChess();			
			}else if (Global.mode.equals(ChessMode.NETWORK)) {
				System.out.println(Global.regretTimes);
				//網(wǎng)絡(luò)模式下,一方選擇悔棋,發(fā)送悔棋消息給另一方,按鈕為名稱為悔棋,發(fā)送方同意悔棋,消息次數(shù)為第一次
				NetUtils.sendMessage(new ButtonMessage("悔	棋", true, MessageTimes.FIRST));
			}
			break;
		case "退	出":
			exitGame();
			break;
		case "<":
			openChessScoreLast();
			break;
		case ">":
			openChessScoreNext();
			break;
		case "x":
			openChessScoreAll();
			break;
		}
		
	}
	/**
	 * 	打開棋譜,點擊x,顯示所有棋子
	 * @author Dracarys
	 */
	private void openChessScoreAll() {
		for (int j = i; j < chessList.size(); j++) {
			pane.getChildren().add(chessList.get(j));
		}
		pane.getChildren().remove(36);
		pane.getChildren().remove(36);
		pane.getChildren().remove(36);
	}
	/**
	 * 	打開棋譜,點擊上一步按鈕
	 * @author Dracarys
	 */
	private void openChessScoreLast() {
		if (i == 0) {
			return;
		}
		pane.getChildren().remove(pane.getChildren().size()-1);
		i--;
		
	}
	/**
	 * 	打開棋譜,點擊下一步按鈕
	 * @author Dracarys
	 */
	private void openChessScoreNext() {
		if (i == chessList.size()) {
			pane.getChildren().remove(36);
			pane.getChildren().remove(36);
			pane.getChildren().remove(36);
			return;
		}
		Circle chess = chessList.get(i);
		pane.getChildren().add(chess);
		i++;
	}
	
}

  

總結(jié)

以上是生活随笔為你收集整理的JavaFx-----五子棋(单机版和对战版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。