Java FX小项目----国际象棋
今天为大家介绍一个简单的Java FX练手项目,使用Java FX开发国际象棋。首先我们要知道国际象棋的基本规则和玩法,类似于我们的中国象棋,最重要的就是保护王,如果王被对方吃掉了,那就输了。https://lichess.org/
在上面这个网站可以学习相关规则和进行试玩。
这个项目使用到的主要有面向对象编程、接口、事件驱动编程、集合框架、Java FX的画布。主要分为:
- 实体层:储存数据例如棋子状态。
- 视图层:使用面板来显示图像。
- 逻辑层:按规则对单击事件进行处理。
1、运行结果
2、项目包

3、代码
- 主程序:Main
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import sample.controller.Controller;
import sample.view.broadPane;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("InternationalChess!");
broadPane pane = new broadPane(60);
pane.setOnMouseClicked(new Controller(pane));
primaryStage.setScene(new Scene(pane, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
- 实体层:
chesspiece
package sample.entity;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import sample.entity.strategy.MoveStrategy;
public class chessPiece {
//棋子坐标
private int x;
private int y;
private double cellLen = 60;
//棋子类型,记录了对应图标的绝对路径
private chessType chessType;
//该棋子是否被选中
private boolean selected;
//棋子移动的策略
private MoveStrategy moveStrategy;
private ImageView imageView;
public chessPiece(int x, int y, sample.entity.chessType chessType, MoveStrategy moveStrategy) {
this.x = x;
this.y = y;
this.chessType = chessType;
this.moveStrategy = moveStrategy;
Image image = new Image(chessType.getPath());
imageView = new ImageView(image);
}
/**
* 依靠MoveStrategy 进行移动
* @param x
* @param y
*/
public void move(int x,int y){
this.x = x;
this.y = y;
this.imageView.setX(x*cellLen);
this.imageView.setY(y*cellLen);
this.setSelected(false);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public sample.entity.chessType getChessType() {
return chessType;
}
public boolean isSelected() {
return selected;
}
public MoveStrategy getMoveStrategy() {
return moveStrategy;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public ImageView getImageView() {
return imageView;
}
@Override
public String toString() {
return "chessPiece{" +
"chessType=" + chessType +
'}';
}
}
chessType
package sample.entity;
public enum chessType{
//黑方棋子及其图片路径
blackBishop("file:D:\\Java\\作业\\国际象棋\\images\\blackBishop.png"),
blackKing("file:D:\\Java\\作业\\国际象棋\\images\\blackKing.png"),
blackKnight("file:D:\\Java\\作业\\国际象棋\\images\\blackKnight.png"),
blackPawn("file:D:\\Java\\作业\\国际象棋\\images\\blackPawn.png"),
blackQueue("file:D:\\Java\\作业\\国际象棋\\images\\blackQueen.png"),
blackRook("file:D:\\Java\\作业\\国际象棋\\images\\blackRook.png"),
//白方棋子及其图片路径
whiteBishop("file:D:\\Java\\作业\\国际象棋\\images\\whiteBishop.png"),
whiteKing("file:D:\\Java\\作业\\国际象棋\\images\\whiteKing.png"),
whiteKnight("file:D:\\Java\\作业\\国际象棋\\images\\whiteKnight.png"),
whitePawn("file:D:\\Java\\作业\\国际象棋\\images\\whitePawn.png"),
whiteQueen("file:D:\\Java\\作业\\国际象棋\\images\\whiteQueen.png"),
whiteRook("file:D:\\Java\\作业\\国际象棋\\images\\whiteRook.png");
//
private String path;
private chessType(String s){
this.path = s;
}
public String getPath() {
return path;
}
}
MoveStrategy接口:让棋子按规则移动
package sample.entity.strategy;
import sample.entity.chessPiece;
public interface MoveStrategy {
public boolean move(chessPiece currentChessPiece,int[][] chess,int x,int y);
}
具体实现如:皇后的移动策略
package sample.entity.strategy;
import sample.entity.chessPiece;
public class QueenStrategy implements MoveStrategy {
@Override
public boolean move(chessPiece currentChessPiece,int[][] chess,int x,int y){
//进行移动
int x1 = currentChessPiece.getX();
int y1 = currentChessPiece.getY();
if(x==x1 || y==y1 || Math.abs(x-x1)==(Math.abs(y-y1))){
if(isEmpty(x1,y1,x,y,chess)){
currentChessPiece.move(x,y);
return true;
}
}
return false;
}
//判断两个点的连线上是否有棋子
public boolean isEmpty(int x,int y,int x1,int y1,int[][] chess){
if(x<x1&&y<y1){
for(int i=1;i<(x1-x);i++)
if(chess[y+i][x+i]!=0)
return false;
}
else if(x==x1&&y<y1){
for(int i=1;i<(x1-x);i++)
if(chess[y+i][x]!=0)
return false;
}
else if(x<x1&&y>y1){
for(int i=1;i<(x1-x);i++)
if(chess[y-i][x+i]!=0)
return false;
}
else if(x==x1&&y>y1){
for(int i=1;i<(x1-x);i++)
if(chess[y-i][x]!=0)
return false;
}
else if(x>x1&&y<y1){
for(int i=1;i<(x-x1);i++)
if(chess[y+i][x-i]!=0)
return false;
}
else if(x>x1&&y==y1){
for(int i=1;i<(x-x1);i++)
if(chess[y][x-i]!=0)
return false;
}
else if (x>x1&&y>y1){
for(int i=1;i<(x-x1);i++)
if(chess[y-i][x-i]!=0)
return false;
}
else if (x>x1&&y==y1){
for(int i=1;i<(x-x1);i++)
if(chess[y][x-i]!=0)
return false;
}
return true;
}
}
- 视图层
package sample.view;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import sample.entity.chessPiece;
import sample.entity.chessType;
import sample.entity.strategy.*;
import java.util.ArrayList;
public class broadPane extends Pane {
//棋子列表
private ArrayList whiteChessList = new ArrayList<chessPiece>();
private ArrayList blackChessList = new ArrayList<chessPiece>();
//目前持方,对棋子进行操作,初始为白方先走
private String currentSide = "W";
private Canvas canvas;
private GraphicsContext gc;
private double cellLen;
//生成国际象棋对象
public broadPane(double cellLen) {
//初始化画布,背景
this.canvas = new Canvas(10*cellLen,10*cellLen);
this.gc = canvas.getGraphicsContext2D();
this.cellLen = cellLen;
getChildren().add(canvas);
//初始化国际象棋
initChess();
}
/**
* 初始化国际象棋:
* 1、绘制棋盘背景
* 2、创建棋子列表
*/
public void initChess(){
drawBackground();
initChessPiece();
}
/**
* 初始化棋子
*/
public void initChessPiece(){
//初始化黑色棋子
blackPawn();
blackKing();
blackQueue();
blackBishop();
blackKnight();
blackRook();
//初始化白色棋子
whitePawn();
whiteKing();
whiteQueue();
whiteBishop();
whiteKnight();
whiteRook();
}
//对图标的位置和形状进行裁剪放置
public void reshapeImageView(int x,int y,chessPiece piece){
piece.getImageView().setX(x*cellLen);
piece.getImageView().setY(y*cellLen);
piece.getImageView().setFitHeight(cellLen);
piece.getImageView().setFitWidth(cellLen);
}
//初始化8个黑色士兵
public void blackPawn(){
for(int i=0;i<8;i++){
chessPiece piece = new chessPiece(i,1, chessType.blackPawn,new blackPawnStrategy());
blackChessList.add(piece);
reshapeImageView(i,1,piece);
getChildren().add(piece.getImageView());
}
}
//初始化黑国王
public void blackKing(){
chessPiece piece = new chessPiece(4,0,chessType.blackKing,new KingStrategy());
blackChessList.add(piece);
reshapeImageView(4,0,piece);
blackChessList.add(piece);
getChildren().add(piece.getImageView());
}
//初始化黑色皇后
public void blackQueue(){
chessPiece piece = new chessPiece(3,0,chessType.blackQueue,new QueenStrategy());
blackChessList.add(piece);
reshapeImageView(3,0,piece);
getChildren().add(piece.getImageView());
}
//初始化黑色的马
public void blackKnight(){
chessPiece piece = new chessPiece(1,0,chessType.blackKnight,new KnightStrategy());
blackChessList.add(piece);
reshapeImageView(1,0,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(6,0,chessType.blackKnight,new KnightStrategy());
blackChessList.add(piece1);
reshapeImageView(6,0,piece1);
getChildren().add(piece1.getImageView());
}
//初始化黑色的象
public void blackBishop(){
chessPiece piece = new chessPiece(2,0,chessType.blackBishop,new BishopStrategy());
blackChessList.add(piece);
reshapeImageView(2,0,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(5,0,chessType.blackBishop,new BishopStrategy());
blackChessList.add(piece1);
reshapeImageView(5,0,piece1);
getChildren().add(piece1.getImageView());
}
//初始化黑色的车
public void blackRook(){
chessPiece piece = new chessPiece(0,0,chessType.blackRook,new RookStrategy());
blackChessList.add(piece);
reshapeImageView(0,0,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(7,0,chessType.blackRook,new RookStrategy());
blackChessList.add(piece1);
reshapeImageView(7,0,piece1);
getChildren().add(piece1.getImageView());
}
//初始化8个白色士兵
public void whitePawn(){
for(int i=0;i<8;i++){
chessPiece piece = new chessPiece(i,6, chessType.whitePawn,new whitePawnStrategy());
whiteChessList.add(piece);
reshapeImageView(i,6,piece);
getChildren().add(piece.getImageView());
}
}
//初始化白国王
public void whiteKing(){
chessPiece piece = new chessPiece(4,7,chessType.whiteKing,new KingStrategy());
whiteChessList.add(piece);
reshapeImageView(4,7,piece);
getChildren().add(piece.getImageView());
}
//初始化白色皇后
public void whiteQueue(){
chessPiece piece = new chessPiece(3,7,chessType.whiteQueen,new QueenStrategy());
whiteChessList.add(piece);
reshapeImageView(3,7,piece);
getChildren().add(piece.getImageView());
}
//初始化白色的马
public void whiteKnight(){
chessPiece piece = new chessPiece(1,7,chessType.whiteKnight,new KnightStrategy());
whiteChessList.add(piece);
reshapeImageView(1,7,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(6,7,chessType.whiteKnight,new KnightStrategy());
whiteChessList.add(piece1);
reshapeImageView(6,7,piece1);
getChildren().add(piece1.getImageView());
}
//初始化白色的象
public void whiteBishop(){
chessPiece piece = new chessPiece(2,7,chessType.whiteBishop,new BishopStrategy());
whiteChessList.add(piece);
reshapeImageView(2,7,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(5,7,chessType.whiteBishop,new BishopStrategy());
whiteChessList.add(piece1);
reshapeImageView(5,7,piece1);
getChildren().add(piece1.getImageView());
}
//初始化白色的车
public void whiteRook(){
chessPiece piece = new chessPiece(0,7,chessType.whiteRook,new RookStrategy());
whiteChessList.add(piece);
reshapeImageView(0,7,piece);
getChildren().add(piece.getImageView());
chessPiece piece1 = new chessPiece(7,7,chessType.whiteRook,new RookStrategy());
whiteChessList.add(piece1);
reshapeImageView(7,7,piece1);
getChildren().add(piece1.getImageView());
}
/**
* 绘制国际象棋背景
*/
public void drawBackground(){
//棋盘颜色设置
Color a = new Color(181/255.0,136/255.0,99/255.0,1);
Color b = new Color(240/255.0,217/255.0,181/255.0,1);
for (int i=0;i<8;i++)
for(int j=0;j<8;j++) {
if((i+j)%2==0)
gc.setFill(b);
else
gc.setFill(a);
gc.fillRect(i*cellLen,j*cellLen,cellLen,cellLen);
}
}
public ArrayList getWhiteChessList() {
return whiteChessList;
}
public ArrayList getBlackChessList() {
return blackChessList;
}
public double getCellLen() {
return cellLen;
}
public String getCurrentSide() {
return currentSide;
}
public void setCurrentSide(String currentSide) {
this.currentSide = currentSide;
}
}
- 控制层
package sample.controller;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;
import sample.entity.chessPiece;
import sample.entity.chessType;
import sample.entity.strategy.MoveStrategy;
import sample.view.broadPane;
public class Controller implements EventHandler<MouseEvent>{
private broadPane broadPane;
private int[][] chess = new int[8][8];
public Controller(sample.view.broadPane broadPane) {
this.broadPane = broadPane;
}
@Override
public void handle(MouseEvent event) {
refresh();
//获取鼠标单击坐标,转化为格子的坐标
int x = (int)(event.getX()/broadPane.getCellLen());
int y = (int)(event.getY()/broadPane.getCellLen());
//点击位置超出了棋盘的范围,不进行响应
if(x>7||y>7)
return ;
//如果没有选中棋子,进行棋子选择
if(isSelected()==null){
chessPiece piece = isEmpty(x,y);
//该座标无棋子
if(piece==null)
return;
//将该棋子设为选中
piece.setSelected(true);
}
//否则进行移动,或重选需要的移动棋子
else{
chessPiece currentPiece = isSelected();
chessPiece newPiece = isEmpty(x,y);
//持方没有重选棋子,进行移动判断
if(newPiece==null){
//点击坐标的棋子
chessPiece nextPiece = getPiece(x,y);
//使用移动策略进行移动或吃子
MoveStrategy moveStrategy = currentPiece.getMoveStrategy();
if(moveStrategy.move(currentPiece,chess,x,y)){
//如果成功吃子或者移动,则更换持方
if(broadPane.getCurrentSide().equals("W"))
broadPane.setCurrentSide("B");
else
broadPane.setCurrentSide("W");
//如果是吃子,则nextPiece存在,需要将其移出棋子列表,并去除其图像
if(nextPiece!=null){
isGameOver(nextPiece);
remove(nextPiece);
}
}
}
//重选了棋子
else{
currentPiece.setSelected(false);
newPiece.setSelected(true);
}
}
}
/**
* 持放是否已经选择了一个棋子
* 如果当前持放是白方,返回白方是否选中了一个需要进行移动的棋子
* @return 返回被选中的棋子,如果没有则返回null
*/
public chessPiece isSelected(){
if(broadPane.getCurrentSide().equals("W")){
for(int i=0;i<broadPane.getWhiteChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getWhiteChessList().get(i);
if(piece.isSelected())
return piece;
}
}
else{
for(int i=0;i<broadPane.getBlackChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getBlackChessList().get(i);
if(piece.isSelected())
return piece;
}
}
return null;
}
/**
* 返回当前持放在x,y的棋子
* @param x
* @param y
* @return
*/
public chessPiece isEmpty(int x, int y){
//如果当前持放是白方,返回该座标是否有白方棋子
if(broadPane.getCurrentSide().equals("W")){
for(int i=0;i<broadPane.getWhiteChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getWhiteChessList().get(i);
if(piece.getX()==x && piece.getY()==y)
return piece;
}
}
//如果当前持放是黑方,返回该座标是否有黑方棋子
else{
for(int i=0;i<broadPane.getBlackChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getBlackChessList().get(i);
if(piece.getX()==x && piece.getY()==y)
return piece;
}
}
return null;
}
/**
* 获得棋盘上坐标x,y上的棋子,如果不存在棋子,则返回null
* @param x
* @param y
* @return
*/
public chessPiece getPiece(int x, int y){
for(int i=0;i<broadPane.getWhiteChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getWhiteChessList().get(i);
if(piece.getX()==x && piece.getY()==y)
return piece;
}
for(int i=0;i<broadPane.getBlackChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getBlackChessList().get(i);
if(piece.getX()==x && piece.getY()==y)
return piece;
}
return null;
}
public void remove(chessPiece piece){
piece.getImageView().setImage(null);
if(broadPane.getCurrentSide().equals("B")){
for(int i=0;i<broadPane.getBlackChessList().size();i++){
chessPiece piece1 = (chessPiece) broadPane.getBlackChessList().get(i);
if(piece.equals(piece1)){
broadPane.getBlackChessList().remove(i);
break;
}
}
}
else{
for(int i=0;i<broadPane.getWhiteChessList().size();i++){
chessPiece piece1 = (chessPiece) broadPane.getWhiteChessList().get(i);
if(piece.equals(piece1)){
broadPane.getWhiteChessList().remove(i);
break;
}
}
}
}
//更新棋盘数组
public void refresh(){
//初始化棋盘数组
for(int i=0;i<8;i++)
for(int j=0;j<8;j++){
chess[i][j] = 0;
}
for(int i=0;i<broadPane.getWhiteChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getWhiteChessList().get(i);
chess[piece.getY()][piece.getX()] = 1;
}
for(int i=0;i<broadPane.getBlackChessList().size();i++){
chessPiece piece = (chessPiece) broadPane.getBlackChessList().get(i);
chess[piece.getY()][piece.getX()] = 2;
}
}
//判断游戏是否结束
public void isGameOver(chessPiece piece){
if(piece.getChessType().equals(chessType.blackKing) || piece.getChessType().equals(chessType.whiteKing )){
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("游戏结束!!");
String content = broadPane.getCurrentSide().equals("W")? "获胜者为黑方!!!":"获胜者为白方!!!";
alert.setContentText(content);
alert.show();
}
}
}
能看到这里的小伙伴估计对JavaFX也是真爱了!!
感谢阅读!
https://github.com/zouqg/InternationalChess.git