Я не уверен, что знаю, что вы подразумеваете под «задержкой» здесь. Вам просто нужно управлять всем с помощью обработчиков событий и следить за тем, куда кусок перемещается и перемещается. Затем проверьте правильность, когда пользователь попытается выполнить переход (как правило, высвободив перетаскивание).
Вот очень простой план (один игрок просто двигается). В реальной жизни, конечно, квадратное состояние (occupied
) было бы более сложным (два игрока и т. Д.), Равно как и проверка валидации. Но это должно дать вам представление.
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.css.PseudoClass;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class CheckersExample extends Application {
private static final int BOARD_SIZE = 10 ;
private static final int SQUARE_SIZE = 60 ;
private static final int PIECE_RADIUS = 25 ;
@Override
public void start(Stage primaryStage) {
// Use a GridPane for the board:
GridPane board = new GridPane();
// track where move is made from and to
ObjectProperty<Square> moveFrom = new SimpleObjectProperty<>();
ObjectProperty<Square> moveTo = new SimpleObjectProperty<>();
// Create the squares and add views of them to the grid pane:
for (int y=0; y<BOARD_SIZE; y++) {
for (int x=0; x<BOARD_SIZE; x++) {
Square square = new Square(x, y);
board.add(square.getView(), x, y);
// alternate squares in last 3 rows are occupied:
if (y >= BOARD_SIZE-3 && (x + y) % 2 == 1) {
square.setOccupied(true);
}
// add event handlers for dragging to enable moving pieces:
setUpDraggingForMove(square, moveFrom, moveTo);
}
}
BorderPane root = new BorderPane(board);
Scene scene = new Scene(root);
scene.getStylesheets().add("checkers.css");
primaryStage.setScene(scene);
primaryStage.show();
}
private void setUpDraggingForMove(Square square, ObjectProperty<Square> moveFrom,
ObjectProperty<Square> moveTo) {
// CSS pseudoclass for highlighting squares before moving to them:
PseudoClass highlight = PseudoClass.getPseudoClass("highlight");
// when starting drag, if square has a piece, set the moveFrom:
square.getView().setOnDragDetected(event -> {
if (square.isOccupied()) {
moveFrom.set(square) ;
// this enables drag events to other nodes (squares):
square.getView().startFullDrag();
}
});
// if dragging onto a square that's a valid move, highlight it and set the moveTo:
square.getView().setOnMouseDragEntered(event -> {
if (moveValid(moveFrom.get(), square)) {
square.getView().pseudoClassStateChanged(highlight, true);
moveTo.set(square);
}
});
// when dragging off a square, un-highlight it and unset the moveTo:
square.getView().setOnMouseDragExited(event -> {
square.getView().pseudoClassStateChanged(highlight, false);
moveTo.set(null);
});
// when releasing, if the move is valid, set the moveFrom to be unoccupied and the
// moveTo to be occupied:
square.getView().setOnMouseReleased(event -> {
if (moveValid(moveFrom.get(), moveTo.get())) {
moveFrom.get().setOccupied(false);
moveTo.get().setOccupied(true);
}
moveFrom.set(null);
moveTo.set(null);
});
}
// check validity of move:
private boolean moveValid(Square from, Square to) {
if (from == null || // no from
to == null || // no to
!from.isOccupied() || // from occupied
to.isOccupied() || // to occupied
from.getY() - to.getY() != 1 || // not moving forward
Math.abs(from.getX() - to.getX()) != 1) // not moving sideways
{
return false ;
} else {
return true ;
}
}
// represents a square on the board. Encapsulates its position (x and y),
// whether or not it contains a piece (occupied)
// and exposes a UI component representing it (view):
private static class Square {
private final int x ;
private final int y ;
private final BooleanProperty occupied ;
private final StackPane view ;
public Square(int x, int y) {
this.x = x ;
this.y = y ;
this.occupied = new SimpleBooleanProperty(this, "occupied", false);
this.view = createView();
}
private StackPane createView() {
// use a StackPane as the base view:
StackPane view = new StackPane();
view.getStyleClass().add("square");
// pseudoclass to enable alternate color on alternate squares:
PseudoClass oddClass = PseudoClass.getPseudoClass("odd");
// fill GridPane cell:
GridPane.setFillHeight(view, true);
GridPane.setFillWidth(view, true);
// fix size:
view.setMinSize(SQUARE_SIZE, SQUARE_SIZE);
view.setMaxSize(SQUARE_SIZE, SQUARE_SIZE);
// set pseudoclass state for "odd" squares:
if ((x + y) % 2 == 0) {
view.pseudoClassStateChanged(oddClass, true);
}
// add piece to stack pane...
Circle piece = new Circle(SQUARE_SIZE/2, SQUARE_SIZE/2, PIECE_RADIUS);
piece.getStyleClass().add("piece");
view.getChildren().add(piece);
// .. but only actually display it if the square is occupied:
piece.visibleProperty().bind(occupied);
return view ;
}
public Node getView() {
return view ;
}
public int getX() {
return x ;
}
public int getY() {
return y ;
}
public final BooleanProperty occupiedProperty() {
return this.occupied;
}
public final boolean isOccupied() {
return this.occupiedProperty().get();
}
public final void setOccupied(final boolean occupied) {
this.occupiedProperty().set(occupied);
}
}
public static void main(String[] args) {
launch(args);
}
}
checkers.css:
.root {
/* and.. breathe... */
-fx-padding: 40px ;
}
.square {
/* use a looked-up color for the main background of a square,
so it's easy to change */
-square-background: antiquewhite ;
/* nest some backgrounds to give the effect of a raised border: */
-fx-background-color: white, lightgray, darkgray, black, -square-background ;
-fx-background-insets: 0px, 1px 1px 0px 0px, 2px 2px 1px 1px, 4px 4px 2px 2px, 5px 5px 3px 3px ;
}
.square:odd {
/* change the main background on "odd" squares: */
-square-background: cornflowerblue ;
}
.square:highlight {
/* and change it again for highlighted squares: */
-square-background: lightgoldenrodyellow ;
}
.piece {
/* color for pieces: */
-fx-fill: steelblue ;
}
Вы должны ссылаться на проверку достоверности на ход игрока в обработчик событий, который захватывает игрока ход. Возможно, посмотрите на мою версию [Tic Tac Toe (Noughts and Crosses)] (https://github.com/james-d/TicTacToe) в качестве примера. –