用javafx写一个拼图游戏,要求鼠标点击移动,能实时显示所走步数和所用时间.
时间: 2024-02-13 15:03:40 浏览: 120
拼图游戏,采用JavaFx
好的,下面我将根据您的要求,提供一个简单的 JavaFX 拼图游戏的实现方案。
首先,我们需要准备一张图片,用于拼图。假设我们选择了一张 640x640 的图片,将其分割成 16 个小块,每个小块大小为 160x160。
接下来,我们需要创建一个 UI 界面,用于显示拼图的图片和游戏信息。这个界面可以使用 VBox、HBox、ImageView、Label 等控件来实现。
代码示例:
```java
public class PuzzleGame extends Application {
private static final int NUM_ROWS = 4;
private static final int NUM_COLS = 4;
private static final int TILE_SIZE = 160;
private static final int BOARD_SIZE = NUM_ROWS * NUM_COLS;
private int moves;
private long startTime;
private boolean gameStarted;
private Label movesLabel;
private Label timeLabel;
private Pane board;
@Override
public void start(Stage primaryStage) {
// 加载拼图图片
Image image = new Image("puzzle.jpg");
// 创建 UI 界面
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.setSpacing(20);
// 创建游戏信息区域
HBox infoBox = new HBox();
infoBox.setAlignment(Pos.CENTER);
infoBox.setSpacing(40);
// 创建步数信息
movesLabel = new Label("Moves: 0");
movesLabel.setFont(Font.font("Arial", FontWeight.BOLD, 24));
infoBox.getChildren().add(movesLabel);
// 创建时间信息
timeLabel = new Label("Time: 0:00");
timeLabel.setFont(Font.font("Arial", FontWeight.BOLD, 24));
infoBox.getChildren().add(timeLabel);
root.getChildren().add(infoBox);
// 创建拼图板块
board = new Pane();
board.setPrefSize(NUM_COLS * TILE_SIZE, NUM_ROWS * TILE_SIZE);
board.setStyle("-fx-background-color: #cccccc;");
// 将拼图块按序号添加到面板中
for (int i = 0; i < BOARD_SIZE; i++) {
int row = i / NUM_COLS;
int col = i % NUM_COLS;
ImageView tile = new ImageView();
tile.setImage(image);
tile.setViewport(new Rectangle2D(col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE));
tile.setLayoutX(col * TILE_SIZE);
tile.setLayoutY(row * TILE_SIZE);
tile.setUserData(i); // 存储拼图块编号
tile.setOnMouseClicked(this::handleTileClick);
board.getChildren().add(tile);
}
root.getChildren().add(board);
// 显示界面
Scene scene = new Scene(root, 640, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
// 处理拼图块点击事件
private void handleTileClick(MouseEvent event) {
int index = (int) ((ImageView) event.getSource()).getUserData();
if (gameStarted) {
// 计算所走步数和所用时间
moves++;
long elapsedTime = System.currentTimeMillis() - startTime;
String timeStr = String.format("%d:%02d", elapsedTime / 1000 / 60, elapsedTime / 1000 % 60);
// 更新游戏信息
movesLabel.setText("Moves: " + moves);
timeLabel.setText("Time: " + timeStr);
} else {
// 开始游戏
gameStarted = true;
startTime = System.currentTimeMillis();
}
// 移动拼图块
moveTile(index);
}
// 移动拼图块
private void moveTile(int index) {
// 查找空白拼图块的位置
int blankIndex = -1;
for (Node node : board.getChildren()) {
if ((int) node.getUserData() == BOARD_SIZE - 1) {
blankIndex = board.getChildren().indexOf(node);
break;
}
}
// 计算拼图块和空白块的行列差值
int rowDiff = index / NUM_COLS - blankIndex / NUM_COLS;
int colDiff = index % NUM_COLS - blankIndex % NUM_COLS;
// 如果拼图块和空白块不在同一行或同一列,则不能移动
if (rowDiff != 0 && colDiff != 0) {
return;
}
// 如果拼图块和空白块在同一行或同一列,且中间没有其他拼图块,则可以移动
boolean canMove = true;
if (rowDiff == 0) {
int startCol = Math.min(index % NUM_COLS, blankIndex % NUM_COLS);
int endCol = Math.max(index % NUM_COLS, blankIndex % NUM_COLS);
for (int i = startCol + 1; i < endCol; i++) {
Node node = board.getChildren().get(NUM_COLS * (index / NUM_COLS) + i);
if ((int) node.getUserData() != BOARD_SIZE - 1) {
canMove = false;
break;
}
}
} else {
int startRow = Math.min(index / NUM_COLS, blankIndex / NUM_COLS);
int endRow = Math.max(index / NUM_COLS, blankIndex / NUM_COLS);
for (int i = startRow + 1; i < endRow; i++) {
Node node = board.getChildren().get(NUM_COLS * i + (index % NUM_COLS));
if ((int) node.getUserData() != BOARD_SIZE - 1) {
canMove = false;
break;
}
}
}
if (canMove) {
// 交换拼图块和空白块的位置
Node tile = board.getChildren().get(index);
double oldX = tile.getLayoutX();
double oldY = tile.getLayoutY();
tile.setLayoutX(board.getChildren().get(blankIndex).getLayoutX());
tile.setLayoutY(board.getChildren().get(blankIndex).getLayoutY());
board.getChildren().get(blankIndex).setLayoutX(oldX);
board.getChildren().get(blankIndex).setLayoutY(oldY);
}
// 判断游戏是否完成
if (isGameCompleted()) {
// 停止计时器
gameStarted = false;
// 显示完成提示
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Congratulations!");
alert.setHeaderText(null);
alert.setContentText("You have completed the puzzle in " + moves + " moves and " + timeLabel.getText() + "!");
alert.showAndWait();
}
}
// 判断游戏是否完成
private boolean isGameCompleted() {
for (Node node : board.getChildren()) {
if ((int) node.getUserData() != board.getChildren().indexOf(node)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
launch(args);
}
}
```
在上面的代码中,我们首先加载了拼图图片,然后创建了一个 VBox,包含了一个 HBox 和一个 Pane。HBox 用于显示游戏信息,比如所走步数和所用时间,Pane 用于显示拼图块。
在 Pane 中,我们按编号将 16 个拼图块添加到面板中,并为每个拼图块添加了鼠标点击事件监听器。当用户点击某个拼图块时,我们会计算该拼图块和空白块的位置关系,如果可以移动,就会交换两个块的位置。同时,我们会实时更新所走步数和所用时间,并判断游戏是否完成。
在拼图块移动时,我们还需要判断拼图块和空白块之间是否有其他拼图块,如果有,则不能移动。这个判断逻辑比较复杂,需要分别处理拼图块和空白块在同一行和同一列的情况。
最后,当游戏完成后,我们会弹出一个提示框,显示所走步数和所用时间。
阅读全文